Docker Compose部署Spring Boot+MySQL应用遇空指针错误求助
尝试在线部署Spring Boot+MySQL应用,已编写Dockerfile和docker-compose.yml,docker-compose build执行成功,但docker-compose up时出现如下空指针错误(本地运行无问题)。AWS账户存在问题暂无法使用,计划容器化完成后部署至Render或Railway平台。
报错信息:
springboot-app-1 | java.lang.NullPointerException: Cannot invoke "org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(java.sql.SQLException, String)" because the return value of "org.hibernate.resource.transaction.backend.jdbc.internal.JdbcIsolationDelegate.sqlExceptionHelper()" is null
相关配置文件
Dockerfile
# base image containing Java runtime FROM openjdk:17-jdk-alpine # volume pointing to /tmp VOLUME /tmp # JAR file COPY target/bookville_2-0.0.1-SNAPSHOT.jar app.jar # Expose the port EXPOSE 8080 # Run the jar file ENTRYPOINT ["java","-jar","/app.jar"]
docker-compose.yml
version: '3.8' services: springboot-app: build: . ports: - "9090:9090" depends_on: - mysql environment: SPRING_DATASOURCE_URL: jdbc:mysql://mysql:3306/dbname SPRING_DATASOURCE_USERNAME: root SPRING_DATASOURCE_PASSWORD: password mysql: image: mysql:8.0.33 ports: - "3307:3306" environment: MYSQL_ROOT_PASSWORD: password MYSQL_DATABASE: bookville volumes: - mysql-data:/var/lib/mysql volumes: mysql-data:
application.properties
spring.application.name=bookville spring.datasource.url=jdbc:mysql://mysql:3306/bookville spring.datasource.username=root spring.datasource.password=password spring.jpa.hibernate.ddl-auto=update spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver spring.jpa.show-sql=true
1. 修复数据库名称不匹配问题
docker-compose.yml中Spring Boot服务的SPRING_DATASOURCE_URL指定的数据库是dbname,但MySQL容器初始化创建的数据库是bookville,同时application.properties里的URL也是bookville。环境变量会覆盖配置文件,导致应用尝试连接不存在的数据库,进而引发Hibernate的空指针异常。
修改docker-compose.yml中Spring Boot服务的环境变量:
SPRING_DATASOURCE_URL: jdbc:mysql://mysql:3306/bookville
2. 解决MySQL启动延迟问题
depends_on仅保证容器启动顺序,不确保MySQL服务完全就绪。Spring Boot启动时若连接未就绪的MySQL,会触发连接异常,最终导致空指针。
方案A:添加启动等待脚本
在项目根目录添加wait-for-it.sh脚本(采用标准的wait-for-it实现逻辑),修改Dockerfile引入等待逻辑:
FROM openjdk:17-jdk-alpine RUN apk add --no-cache bash COPY wait-for-it.sh /wait-for-it.sh RUN chmod +x /wait-for-it.sh VOLUME /tmp COPY target/bookville_2-0.0.1-SNAPSHOT.jar app.jar EXPOSE 8080 ENTRYPOINT ["/wait-for-it.sh", "mysql:3306", "--", "java", "-jar", "/app.jar"]
方案B:配置连接池重试机制
在application.properties中添加连接池参数,让应用自动重试连接:
# 连接超时时间 spring.datasource.hikari.connection-timeout=60000 # 最大连接数 spring.datasource.hikari.maximum-pool-size=5 # 禁用自动提交 spring.jpa.properties.hibernate.connection.provider_disables_autocommit=true # 连接校验 spring.datasource.test-on-borrow=true spring.datasource.validation-query=SELECT 1
3. 统一端口配置
Dockerfile中EXPOSE 8080,但docker-compose.yml映射的是9090:9090,需确保端口一致:
- 若应用默认监听8080,修改docker-compose.yml的端口映射为
9090:8080 - 若要使用9090端口,在application.properties中添加
server.port=9090
4. Render/Railway部署提前适配
这两个平台推荐使用托管数据库服务而非容器化MySQL,优化部署流程:
- 移除docker-compose.yml中的MySQL服务,改用平台提供的MySQL实例
- 配置平台环境变量,替换Spring Boot的数据库连接参数(URL、用户名、密码)
- 移除本地端口映射,平台会自动分配对外访问端口
内容的提问来源于stack exchange,提问作者Chinecherem Ubawike

