1. 简介
本教程将演示如何使用流行的开源数据库 PostgreSQL 来运行一个 Spring Boot 应用。在之前的文章中,我们介绍了 Docker Compose 如何用于管理多个容器。因此,我们不会单独安装 PostgreSQL,而是使用 Docker Compose 来统一管理 Spring Boot 和 PostgreSQL 的运行环境。
2. 创建 Spring Boot 项目
首先访问 Spring Initializer 创建一个新的 Spring Boot 项目。我们需要添加以下两个依赖项:
- PostgreSQL Driver
- Spring Data JPA
下载 ZIP 文件并解压后,尝试运行项目:
./mvnw spring-boot:run
不出意外,你会看到如下错误信息:
***************************
APPLICATION FAILED TO START
***************************
Description:
Failed to configure a DataSource: 'url' attribute is not specified and no embedded datasource could be configured.
Reason: Failed to determine a suitable driver class
✅ 踩坑提示:这是因为没有配置数据源导致的启动失败。
3. 编写 Dockerfile
在使用 Docker Compose 启动 PostgreSQL 之前,我们需要先将 Spring Boot 应用打包成 Docker 镜像。首先将其打包为 JAR 文件:
./mvnw clean package -DskipTests
⚠️ 注意这里跳过了测试,因为没有数据库连接会导致测试失败。
接着,在 src/main/docker
目录下创建 Dockerfile:
FROM adoptopenjdk:11-jre-hotspot
ARG JAR_FILE=*.jar
COPY ${JAR_FILE} application.jar
ENTRYPOINT ["java", "-jar", "application.jar"]
这个 Dockerfile 做了以下几件事:
- 使用 AdoptOpenJDK 的 Java 11 镜像;
- 将构建好的 JAR 包复制进容器,并命名为
application.jar
; - 设置入口点,启动应用。
4. 编写 docker-compose.yml
现在来编写 Docker Compose 配置文件 docker-compose.yml
,放在 src/main/docker
目录中:
version: '2'
services:
app:
image: 'docker-spring-boot-postgres:latest'
build:
context: .
container_name: app
depends_on:
- db
environment:
- SPRING_DATASOURCE_URL=jdbc:postgresql://db:5432/compose-postgres
- SPRING_DATASOURCE_USERNAME=compose-postgres
- SPRING_DATASOURCE_PASSWORD=compose-postgres
- SPRING_JPA_HIBERNATE_DDL_AUTO=update
db:
image: 'postgres:13.1-alpine'
container_name: db
environment:
- POSTGRES_USER=compose-postgres
- POSTGRES_PASSWORD=compose-postgres
📌 关键点说明:
4.1 应用服务(app)
- 使用自定义镜像
docker-spring-boot-postgres:latest
; - 构建上下文是当前目录;
- 依赖于
db
容器,确保先启动数据库; - 设置了 Spring Boot 数据源相关的环境变量;
- Hibernate 自动更新表结构(DDL_AUTO=update)。
4.2 数据库服务(db)
- 使用官方 PostgreSQL 13.1 Alpine 版本;
- 用户名和密码均为
compose-postgres
; - 数据库名也通过 URL 指定为
compose-postgres
。
5. 使用 Docker Compose 启动应用
执行以下命令启动整个服务栈:
docker-compose up
首次运行时会自动构建 Spring Boot 镜像、启动 PostgreSQL 容器,最后运行我们的应用。输出类似如下:
Starting DemoApplication v0.0.1-SNAPSHOT using Java 11.0.9 on f94e79a2c9fc with PID 1 (/application.jar started by root in /)
[...]
Finished Spring Data repository scanning in 28 ms. Found 0 JPA repository interfaces.
[...]
Started DemoApplication in 4.751 seconds (JVM running for 6.512)
如果要停止所有容器,请按 [Ctrl-C]
,然后执行:
docker-compose down
6. 创建实体类与 Repository
为了操作 PostgreSQL 数据库,我们创建一个简单的客户实体类:
@Entity
@Table(name = "customer")
public class Customer {
@Id
@GeneratedValue
private long id;
@Column(name = "first_name", nullable = false)
private String firstName;
@Column(name = "last_name", nullable = false)
private String lastName;
}
接着定义对应的 Repository 接口:
public interface CustomerRepository extends JpaRepository<Customer, Long> { }
最后在主类中注入该 Repository 并进行测试:
@SpringBootApplication
public class DemoApplication {
@Autowired
private CustomerRepository repository;
@EventListener(ApplicationReadyEvent.class)
public void runAfterStartup() {
List allCustomers = this.repository.findAll();
logger.info("Number of customers: " + allCustomers.size());
Customer newCustomer = new Customer();
newCustomer.setFirstName("John");
newCustomer.setLastName("Doe");
logger.info("Saving new customer...");
this.repository.save(newCustomer);
allCustomers = this.repository.findAll();
logger.info("Number of customers: " + allCustomers.size());
}
}
📌 逻辑说明:
- 查询当前客户数量(初始为 0);
- 创建并保存一个新客户;
- 再次查询,确认客户数量变为 1。
7. 重新构建并再次运行
修改代码后需要重新构建镜像。回到项目根目录执行:
./mvnw clean package -DskipTests
cp target/docker-spring-boot-postgres-0.0.1-SNAPSHOT.jar src/main/docker
然后进入 src/main/docker
目录删除旧镜像以强制重建:
cd src/main/docker
docker-compose down
docker rmi docker-spring-boot-postgres:latest
docker-compose up
此时再次运行,可以看到应用正确识别到了 Repository,并成功保存了一条客户记录:
Finished Spring Data repository scanning in 180 ms. Found 1 JPA repository interfaces.
[...]
Number of customers: 0
Saving new customer...
Number of customers: 1
✅ 小结:每次更新代码后记得清理旧镜像再重新构建,避免缓存问题。
8. 总结
这篇文章带你从零开始搭建了一个基于 Spring Boot + PostgreSQL 的 Docker 化开发环境。我们使用 Docker Compose 统一管理服务容器,简化了本地开发流程。
后续你可以继续扩展功能,比如加入 REST Controller 提供 API 接口,或集成 Flyway 做数据库迁移等。
完整源码可以在这里找到:GitHub 示例项目