【Kotlin + Spring Boot 4 从零到架构师】第 17 篇:PostgreSQL + Docker 环境搭建
本系列定位:零基础入门,从 Kotlin 语法一路到 Spring Boot 4 高级架构(DDD + Modulith),适合 Java 开发者转型,也适合纯新手系统学习。
本篇你将学到
- 用 Docker 快速部署 PostgreSQL 16
- Spring Boot 连接 PostgreSQL 的配置
- HikariCP 连接池的概念与关键参数
- 验证数据库连通性
学完本篇,mini-shop 将从内存存储升级为真正的数据库持久化。
一、安装 Docker
1.1 为什么用 Docker 部署数据库
- 一键部署:不需要在系统上手动安装 PostgreSQL
- 环境隔离:不同项目可以用不同版本的数据库,互不干扰
- 与生产一致:开发环境与生产环境使用相同的 Docker 镜像
- 便于清理:不想要了直接删容器,不污染系统
1.2 安装 Docker
Windows / macOS
- 访问 Docker Desktop 官网
- 下载并安装对应平台的版本
- 启动 Docker Desktop,等待右下角图标变为绿色
Linux(Debian/Ubuntu)
bash
# 官方一键安装脚本
curl -fsSL https://get.docker.com | sh
# 启动 Docker 服务
sudo systemctl start docker
sudo systemctl enable docker
# 验证
docker --version
验证安装成功:终端执行
docker --version,看到版本号即可。
下面是 Docker 部署 PostgreSQL 的整体流程:
#mermaid-svg-yhs1ep4iMHiOd98x{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-yhs1ep4iMHiOd98x .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-yhs1ep4iMHiOd98x .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-yhs1ep4iMHiOd98x .error-icon{fill:#552222;}#mermaid-svg-yhs1ep4iMHiOd98x .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-yhs1ep4iMHiOd98x .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-yhs1ep4iMHiOd98x .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-yhs1ep4iMHiOd98x .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-yhs1ep4iMHiOd98x .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-yhs1ep4iMHiOd98x .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-yhs1ep4iMHiOd98x .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-yhs1ep4iMHiOd98x .marker{fill:#333333;stroke:#333333;}#mermaid-svg-yhs1ep4iMHiOd98x .marker.cross{stroke:#333333;}#mermaid-svg-yhs1ep4iMHiOd98x svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-yhs1ep4iMHiOd98x p{margin:0;}#mermaid-svg-yhs1ep4iMHiOd98x .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-yhs1ep4iMHiOd98x .cluster-label text{fill:#333;}#mermaid-svg-yhs1ep4iMHiOd98x .cluster-label span{color:#333;}#mermaid-svg-yhs1ep4iMHiOd98x .cluster-label span p{background-color:transparent;}#mermaid-svg-yhs1ep4iMHiOd98x .label text,#mermaid-svg-yhs1ep4iMHiOd98x span{fill:#333;color:#333;}#mermaid-svg-yhs1ep4iMHiOd98x .node rect,#mermaid-svg-yhs1ep4iMHiOd98x .node circle,#mermaid-svg-yhs1ep4iMHiOd98x .node ellipse,#mermaid-svg-yhs1ep4iMHiOd98x .node polygon,#mermaid-svg-yhs1ep4iMHiOd98x .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-yhs1ep4iMHiOd98x .rough-node .label text,#mermaid-svg-yhs1ep4iMHiOd98x .node .label text,#mermaid-svg-yhs1ep4iMHiOd98x .image-shape .label,#mermaid-svg-yhs1ep4iMHiOd98x .icon-shape .label{text-anchor:middle;}#mermaid-svg-yhs1ep4iMHiOd98x .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-yhs1ep4iMHiOd98x .rough-node .label,#mermaid-svg-yhs1ep4iMHiOd98x .node .label,#mermaid-svg-yhs1ep4iMHiOd98x .image-shape .label,#mermaid-svg-yhs1ep4iMHiOd98x .icon-shape .label{text-align:center;}#mermaid-svg-yhs1ep4iMHiOd98x .node.clickable{cursor:pointer;}#mermaid-svg-yhs1ep4iMHiOd98x .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-yhs1ep4iMHiOd98x .arrowheadPath{fill:#333333;}#mermaid-svg-yhs1ep4iMHiOd98x .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-yhs1ep4iMHiOd98x .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-yhs1ep4iMHiOd98x .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-yhs1ep4iMHiOd98x .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-yhs1ep4iMHiOd98x .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-yhs1ep4iMHiOd98x .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-yhs1ep4iMHiOd98x .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-yhs1ep4iMHiOd98x .cluster text{fill:#333;}#mermaid-svg-yhs1ep4iMHiOd98x .cluster span{color:#333;}#mermaid-svg-yhs1ep4iMHiOd98x div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-yhs1ep4iMHiOd98x .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-yhs1ep4iMHiOd98x rect.text{fill:none;stroke-width:0;}#mermaid-svg-yhs1ep4iMHiOd98x .icon-shape,#mermaid-svg-yhs1ep4iMHiOd98x .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-yhs1ep4iMHiOd98x .icon-shape p,#mermaid-svg-yhs1ep4iMHiOd98x .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-yhs1ep4iMHiOd98x .icon-shape .label rect,#mermaid-svg-yhs1ep4iMHiOd98x .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-yhs1ep4iMHiOd98x .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-yhs1ep4iMHiOd98x .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-yhs1ep4iMHiOd98x :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} running
stopped
安装 Docker
创建 docker-compose.yml
docker compose up -d
容器状态检查
验证连接
查看日志排查
Spring Boot 连接配置
二、部署 PostgreSQL
2.1 docker-compose 方式(推荐)
在 mini-shop 项目根目录创建 docker-compose.yml:
yaml
version: "3.9"
services:
postgres:
image: postgres:16-alpine
container_name: mini-shop-postgres
environment:
POSTGRES_DB: mini_shop
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres123
ports:
- "5432:5432"
volumes:
- postgres_data:/var/lib/postgresql/data
restart: unless-stopped
volumes:
postgres_data:
| 配置项 | 说明 |
|---|---|
image: postgres:16-alpine |
PostgreSQL 16 的 Alpine 精简版镜像(体积小) |
POSTGRES_DB |
自动创建的数据库名 |
POSTGRES_USER / POSTGRES_PASSWORD |
用户名和密码 |
ports: "5432:5432" |
宿主机端口 → 容器端口映射 |
volumes: postgres_data |
数据持久化------容器删除后数据不丢失 |
2.2 启动数据库
bash
# 在项目根目录执行
docker compose up -d
# -d 表示后台运行
验证容器状态:
bash
docker compose ps
看到 mini-shop-postgres 状态为 running 即可。
2.3 验证数据库连接
bash
# 进入 PostgreSQL 交互终端
docker exec -it mini-shop-postgres psql -U postgres -d mini_shop
# 执行 SQL
\l # 列出所有数据库
\dt # 列出表(目前为空)
\q # 退出
2.4 常用 Docker 命令
bash
# 停止数据库
docker compose stop
# 启动(已创建的容器)
docker compose start
# 停止并删除容器(数据保留在 volume 中)
docker compose down
# 停止并删除容器 + 删除数据(完全重置)
docker compose down -v
# 查看数据库日志
docker compose logs postgres
三、Spring Boot 连接配置
3.1 添加依赖
确保 build.gradle.kts 中有 JPA 和 PostgreSQL 依赖:
kotlin
dependencies {
// Spring Data JPA(包含 Hibernate 7)
implementation("org.springframework.boot:spring-boot-starter-data-jpa")
// PostgreSQL 驱动
runtimeOnly("org.postgresql:postgresql")
// 之前的依赖...
implementation("org.springframework.boot:spring-boot-starter-web")
implementation("org.springframework.boot:spring-boot-starter-validation")
}
3.2 配置数据源
修改 application-dev.yml:
yaml
spring:
datasource:
url: jdbc:postgresql://localhost:5432/mini_shop
username: postgres
password: postgres123
driver-class-name: org.postgresql.Driver
jpa:
# 自动根据实体类生成/更新表结构(开发环境用,生产环境关闭!)
hibernate:
ddl-auto: update
# 在控制台打印 SQL 语句(开发环境调试用)
show-sql: true
properties:
hibernate:
# 格式化 SQL 输出
format_sql: true
# 指定数据库方言
dialect: org.hibernate.dialect.PostgreSQLDialect
3.3 ddl-auto 各值说明
| 值 | 行为 | 适用环境 |
|---|---|---|
none |
不做任何操作 | 生产 |
validate |
只验证实体与表结构是否匹配,不修改 | 生产 |
update |
根据实体自动更新表结构(新增列/表) | 开发 |
create |
每次启动删除并重建所有表 | 测试(会丢数据!) |
create-drop |
启动时创建,退出时删除 | 测试 |
重要警告 :
ddl-auto: update仅限开发环境!生产环境必须用validate或none,通过 Liquibase(第 22 篇)管理表结构变更。
3.4 JPA 与 Hibernate 的关系
JPA(Jakarta Persistence API)
← 标准规范(接口),定义了 ORM 的标准 API
Hibernate
← JPA 的实现之一(最流行的实现)
Spring Data JPA
← 在 JPA 之上再加一层封装(Repository 接口自动实现)
层级关系:Spring Data JPA → JPA(接口)→ Hibernate(实现)→ 数据库。
下面是 JPA 与 Hibernate 的层级关系图:
#mermaid-svg-aOFh1i5SV08uEMB8{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-aOFh1i5SV08uEMB8 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-aOFh1i5SV08uEMB8 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-aOFh1i5SV08uEMB8 .error-icon{fill:#552222;}#mermaid-svg-aOFh1i5SV08uEMB8 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-aOFh1i5SV08uEMB8 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-aOFh1i5SV08uEMB8 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-aOFh1i5SV08uEMB8 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-aOFh1i5SV08uEMB8 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-aOFh1i5SV08uEMB8 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-aOFh1i5SV08uEMB8 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-aOFh1i5SV08uEMB8 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-aOFh1i5SV08uEMB8 .marker.cross{stroke:#333333;}#mermaid-svg-aOFh1i5SV08uEMB8 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-aOFh1i5SV08uEMB8 p{margin:0;}#mermaid-svg-aOFh1i5SV08uEMB8 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-aOFh1i5SV08uEMB8 .cluster-label text{fill:#333;}#mermaid-svg-aOFh1i5SV08uEMB8 .cluster-label span{color:#333;}#mermaid-svg-aOFh1i5SV08uEMB8 .cluster-label span p{background-color:transparent;}#mermaid-svg-aOFh1i5SV08uEMB8 .label text,#mermaid-svg-aOFh1i5SV08uEMB8 span{fill:#333;color:#333;}#mermaid-svg-aOFh1i5SV08uEMB8 .node rect,#mermaid-svg-aOFh1i5SV08uEMB8 .node circle,#mermaid-svg-aOFh1i5SV08uEMB8 .node ellipse,#mermaid-svg-aOFh1i5SV08uEMB8 .node polygon,#mermaid-svg-aOFh1i5SV08uEMB8 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-aOFh1i5SV08uEMB8 .rough-node .label text,#mermaid-svg-aOFh1i5SV08uEMB8 .node .label text,#mermaid-svg-aOFh1i5SV08uEMB8 .image-shape .label,#mermaid-svg-aOFh1i5SV08uEMB8 .icon-shape .label{text-anchor:middle;}#mermaid-svg-aOFh1i5SV08uEMB8 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-aOFh1i5SV08uEMB8 .rough-node .label,#mermaid-svg-aOFh1i5SV08uEMB8 .node .label,#mermaid-svg-aOFh1i5SV08uEMB8 .image-shape .label,#mermaid-svg-aOFh1i5SV08uEMB8 .icon-shape .label{text-align:center;}#mermaid-svg-aOFh1i5SV08uEMB8 .node.clickable{cursor:pointer;}#mermaid-svg-aOFh1i5SV08uEMB8 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-aOFh1i5SV08uEMB8 .arrowheadPath{fill:#333333;}#mermaid-svg-aOFh1i5SV08uEMB8 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-aOFh1i5SV08uEMB8 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-aOFh1i5SV08uEMB8 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-aOFh1i5SV08uEMB8 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-aOFh1i5SV08uEMB8 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-aOFh1i5SV08uEMB8 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-aOFh1i5SV08uEMB8 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-aOFh1i5SV08uEMB8 .cluster text{fill:#333;}#mermaid-svg-aOFh1i5SV08uEMB8 .cluster span{color:#333;}#mermaid-svg-aOFh1i5SV08uEMB8 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-aOFh1i5SV08uEMB8 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-aOFh1i5SV08uEMB8 rect.text{fill:none;stroke-width:0;}#mermaid-svg-aOFh1i5SV08uEMB8 .icon-shape,#mermaid-svg-aOFh1i5SV08uEMB8 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-aOFh1i5SV08uEMB8 .icon-shape p,#mermaid-svg-aOFh1i5SV08uEMB8 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-aOFh1i5SV08uEMB8 .icon-shape .label rect,#mermaid-svg-aOFh1i5SV08uEMB8 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-aOFh1i5SV08uEMB8 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-aOFh1i5SV08uEMB8 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-aOFh1i5SV08uEMB8 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 数据层
实现层
规范层
应用层
调用
标准接口
JDBC 驱动
Spring Data JPA
Repository 接口
JPA
Jakarta Persistence API
Hibernate 7
ORM 框架
PostgreSQL 数据库
四、HikariCP 连接池
4.1 为什么需要连接池
每次数据库操作都创建/销毁 TCP 连接开销很大。连接池预先创建一批连接并复用:
没有连接池:每次请求 → 创建连接 → 执行 SQL → 销毁连接(慢)
有连接池: 每次请求 → 从池中借连接 → 执行 SQL → 归还到池中(快)
4.2 Spring Boot 默认连接池
Spring Boot 默认使用 HikariCP------目前性能最好的 JDBC 连接池,不需要额外配置。
4.3 关键参数调优
yaml
spring:
datasource:
url: jdbc:postgresql://localhost:5432/mini_shop
username: postgres
password: postgres123
hikari:
# 最大连接数(默认 10,生产环境建议 = CPU 核心数 * 2 + 磁盘数)
maximum-pool-size: 10
# 最小空闲连接数(默认 = maximum-pool-size)
minimum-idle: 5
# 连接超时时间(默认 30 秒)
connection-timeout: 30000
# 连接最长存活时间(默认 30 分钟)
max-lifetime: 1800000
# 空闲连接超时(默认 10 分钟)
idle-timeout: 600000
# 连接池名称
pool-name: MiniShopHikariPool
入门建议:开发阶段用默认配置即可。生产调优在模块八(性能调优)中详细讲解。
下面是连接池工作原理的对比图:
#mermaid-svg-RftfIT9BdbUFhqaa{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-RftfIT9BdbUFhqaa .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-RftfIT9BdbUFhqaa .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-RftfIT9BdbUFhqaa .error-icon{fill:#552222;}#mermaid-svg-RftfIT9BdbUFhqaa .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-RftfIT9BdbUFhqaa .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-RftfIT9BdbUFhqaa .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-RftfIT9BdbUFhqaa .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-RftfIT9BdbUFhqaa .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-RftfIT9BdbUFhqaa .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-RftfIT9BdbUFhqaa .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-RftfIT9BdbUFhqaa .marker{fill:#333333;stroke:#333333;}#mermaid-svg-RftfIT9BdbUFhqaa .marker.cross{stroke:#333333;}#mermaid-svg-RftfIT9BdbUFhqaa svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-RftfIT9BdbUFhqaa p{margin:0;}#mermaid-svg-RftfIT9BdbUFhqaa .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-RftfIT9BdbUFhqaa .cluster-label text{fill:#333;}#mermaid-svg-RftfIT9BdbUFhqaa .cluster-label span{color:#333;}#mermaid-svg-RftfIT9BdbUFhqaa .cluster-label span p{background-color:transparent;}#mermaid-svg-RftfIT9BdbUFhqaa .label text,#mermaid-svg-RftfIT9BdbUFhqaa span{fill:#333;color:#333;}#mermaid-svg-RftfIT9BdbUFhqaa .node rect,#mermaid-svg-RftfIT9BdbUFhqaa .node circle,#mermaid-svg-RftfIT9BdbUFhqaa .node ellipse,#mermaid-svg-RftfIT9BdbUFhqaa .node polygon,#mermaid-svg-RftfIT9BdbUFhqaa .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-RftfIT9BdbUFhqaa .rough-node .label text,#mermaid-svg-RftfIT9BdbUFhqaa .node .label text,#mermaid-svg-RftfIT9BdbUFhqaa .image-shape .label,#mermaid-svg-RftfIT9BdbUFhqaa .icon-shape .label{text-anchor:middle;}#mermaid-svg-RftfIT9BdbUFhqaa .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-RftfIT9BdbUFhqaa .rough-node .label,#mermaid-svg-RftfIT9BdbUFhqaa .node .label,#mermaid-svg-RftfIT9BdbUFhqaa .image-shape .label,#mermaid-svg-RftfIT9BdbUFhqaa .icon-shape .label{text-align:center;}#mermaid-svg-RftfIT9BdbUFhqaa .node.clickable{cursor:pointer;}#mermaid-svg-RftfIT9BdbUFhqaa .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-RftfIT9BdbUFhqaa .arrowheadPath{fill:#333333;}#mermaid-svg-RftfIT9BdbUFhqaa .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-RftfIT9BdbUFhqaa .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-RftfIT9BdbUFhqaa .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-RftfIT9BdbUFhqaa .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-RftfIT9BdbUFhqaa .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-RftfIT9BdbUFhqaa .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-RftfIT9BdbUFhqaa .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-RftfIT9BdbUFhqaa .cluster text{fill:#333;}#mermaid-svg-RftfIT9BdbUFhqaa .cluster span{color:#333;}#mermaid-svg-RftfIT9BdbUFhqaa div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-RftfIT9BdbUFhqaa .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-RftfIT9BdbUFhqaa rect.text{fill:none;stroke-width:0;}#mermaid-svg-RftfIT9BdbUFhqaa .icon-shape,#mermaid-svg-RftfIT9BdbUFhqaa .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-RftfIT9BdbUFhqaa .icon-shape p,#mermaid-svg-RftfIT9BdbUFhqaa .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-RftfIT9BdbUFhqaa .icon-shape .label rect,#mermaid-svg-RftfIT9BdbUFhqaa .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-RftfIT9BdbUFhqaa .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-RftfIT9BdbUFhqaa .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-RftfIT9BdbUFhqaa :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 慢
有连接池(HikariCP)
请求到达
从池中借连接
执行 SQL
归还到池中
响应返回
没有连接池
请求到达
创建 TCP 连接
执行 SQL
销毁连接
响应返回
五、连接验证
5.1 启动项目验证
确保 Docker 中 PostgreSQL 已启动,然后运行 Spring Boot 项目。
控制台看到类似日志说明连接成功:
HikariPool-1 - Starting...
HikariPool-1 - Added connection org.postgresql.jdbc.PgConnection@...
HikariPool-1 - Start completed.
5.2 常见连接问题排查
问题一:Connection refused
Connection refused: localhost/127.0.0.1:5432
原因:PostgreSQL 容器没有启动。
bash
# 检查容器状态
docker compose ps
# 如果没有运行,启动它
docker compose up -d
问题二:Authentication failed
FATAL: password authentication failed for user "postgres"
原因:密码不匹配。检查 application-dev.yml 中的密码与 docker-compose.yml 中的 POSTGRES_PASSWORD 是否一致。
如果修改了
docker-compose.yml中的密码,需要先docker compose down -v(删除旧数据卷)再重新docker compose up -d。
问题三:Database does not exist
FATAL: database "mini_shop" does not exist
原因:数据库名不匹配。检查 URL 中的数据库名与 POSTGRES_DB 是否一致。
下面是连接问题排查流程图:
#mermaid-svg-b8HWzdkzerz55MSa{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-b8HWzdkzerz55MSa .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-b8HWzdkzerz55MSa .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-b8HWzdkzerz55MSa .error-icon{fill:#552222;}#mermaid-svg-b8HWzdkzerz55MSa .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-b8HWzdkzerz55MSa .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-b8HWzdkzerz55MSa .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-b8HWzdkzerz55MSa .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-b8HWzdkzerz55MSa .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-b8HWzdkzerz55MSa .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-b8HWzdkzerz55MSa .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-b8HWzdkzerz55MSa .marker{fill:#333333;stroke:#333333;}#mermaid-svg-b8HWzdkzerz55MSa .marker.cross{stroke:#333333;}#mermaid-svg-b8HWzdkzerz55MSa svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-b8HWzdkzerz55MSa p{margin:0;}#mermaid-svg-b8HWzdkzerz55MSa .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-b8HWzdkzerz55MSa .cluster-label text{fill:#333;}#mermaid-svg-b8HWzdkzerz55MSa .cluster-label span{color:#333;}#mermaid-svg-b8HWzdkzerz55MSa .cluster-label span p{background-color:transparent;}#mermaid-svg-b8HWzdkzerz55MSa .label text,#mermaid-svg-b8HWzdkzerz55MSa span{fill:#333;color:#333;}#mermaid-svg-b8HWzdkzerz55MSa .node rect,#mermaid-svg-b8HWzdkzerz55MSa .node circle,#mermaid-svg-b8HWzdkzerz55MSa .node ellipse,#mermaid-svg-b8HWzdkzerz55MSa .node polygon,#mermaid-svg-b8HWzdkzerz55MSa .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-b8HWzdkzerz55MSa .rough-node .label text,#mermaid-svg-b8HWzdkzerz55MSa .node .label text,#mermaid-svg-b8HWzdkzerz55MSa .image-shape .label,#mermaid-svg-b8HWzdkzerz55MSa .icon-shape .label{text-anchor:middle;}#mermaid-svg-b8HWzdkzerz55MSa .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-b8HWzdkzerz55MSa .rough-node .label,#mermaid-svg-b8HWzdkzerz55MSa .node .label,#mermaid-svg-b8HWzdkzerz55MSa .image-shape .label,#mermaid-svg-b8HWzdkzerz55MSa .icon-shape .label{text-align:center;}#mermaid-svg-b8HWzdkzerz55MSa .node.clickable{cursor:pointer;}#mermaid-svg-b8HWzdkzerz55MSa .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-b8HWzdkzerz55MSa .arrowheadPath{fill:#333333;}#mermaid-svg-b8HWzdkzerz55MSa .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-b8HWzdkzerz55MSa .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-b8HWzdkzerz55MSa .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-b8HWzdkzerz55MSa .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-b8HWzdkzerz55MSa .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-b8HWzdkzerz55MSa .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-b8HWzdkzerz55MSa .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-b8HWzdkzerz55MSa .cluster text{fill:#333;}#mermaid-svg-b8HWzdkzerz55MSa .cluster span{color:#333;}#mermaid-svg-b8HWzdkzerz55MSa div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-b8HWzdkzerz55MSa .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-b8HWzdkzerz55MSa rect.text{fill:none;stroke-width:0;}#mermaid-svg-b8HWzdkzerz55MSa .icon-shape,#mermaid-svg-b8HWzdkzerz55MSa .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-b8HWzdkzerz55MSa .icon-shape p,#mermaid-svg-b8HWzdkzerz55MSa .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-b8HWzdkzerz55MSa .icon-shape .label rect,#mermaid-svg-b8HWzdkzerz55MSa .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-b8HWzdkzerz55MSa .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-b8HWzdkzerz55MSa .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-b8HWzdkzerz55MSa :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 是
否
是
否
是
否
连接失败
Connection refused?
检查容器是否运行
docker compose ps
未运行则启动
docker compose up -d
Authentication failed?
检查密码是否一致
application-dev.yml ↔ docker-compose.yml
修改密码后
docker compose down -v 再重启
Database does not exist?
检查数据库名是否一致
URL 中的库名 ↔ POSTGRES_DB
查看完整日志
docker compose logs postgres
连接成功 ✅
六、小结与项目结构
本篇完成后,mini-shop 项目结构:
mini-shop/
├── docker-compose.yml ← PostgreSQL 容器配置
├── build.gradle.kts
├── src/main/
│ ├── kotlin/com/example/minishop/
│ │ ├── MiniShopApplication.kt
│ │ ├── controller/
│ │ ├── service/
│ │ ├── repository/
│ │ ├── dto/
│ │ └── config/
│ └── resources/
│ ├── application.yml
│ └── application-dev.yml ← 数据库连接配置
本篇小结
| 知识点 | 核心内容 |
|---|---|
| Docker 部署 PostgreSQL | docker compose up -d 一键启动 |
| 数据持久化 | Docker Volume 保证容器删除后数据不丢 |
| 连接配置 | spring.datasource 配置 URL/用户名/密码 |
ddl-auto |
update(开发)/ validate(生产) |
| HikariCP | Spring Boot 默认连接池,高性能 |
| JPA → Hibernate | 规范 → 实现的关系 |
| 连接池原理 | 预创建连接复用,避免频繁创建/销毁 |
下篇预告
第 18 篇:Hibernate 7 与 JPA --- 实体映射基础
如何把 Kotlin 类映射为数据库表?
@Entity/@Table/@Id/@Column各自的作用?下一篇将 mini-shop 的商品模型映射到 PostgreSQL。
如果本篇内容对你有帮助,欢迎点赞收藏!有任何疑问,欢迎在评论区交流。