Docker部署Spring Boot后端:仅UserEntity加载成功,其他实体未生成
我正在开发一个Web应用,用Docker构建后端镜像。目前数据库、phpMyAdmin和应用镜像都已成功创建,但只有UserEntity对应的表被创建,其他实体的表无法加载到数据库中。
以下是实体代码:
package org.example.persistence.entity; import lombok.*; import javax.persistence.*; @Entity @Data @Getter @Setter @Builder @AllArgsConstructor @NoArgsConstructor public class ExerciseEntity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "id") private Long id; private String name; private String description; private String imageUrl; } package org.example.persistence.entity; import lombok.Data; import lombok.Getter; import lombok.Setter; import org.example.domain.MessageStatus; import javax.persistence.*; import java.time.LocalDateTime; @Data @Entity @Getter @Setter @Table(name = "messages") public class MessageEntity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @JoinColumn(name = "sender_id") private Long senderId; @JoinColumn(name = "receiver_id") private Long receiverId; @Column(name = "message") private String message; @Column(name = "date") private LocalDateTime date; @Enumerated(EnumType.STRING) @Column(name = "status") private MessageStatus status; } package org.example.persistence.entity; import lombok.*; import java.time.LocalDate; import javax.persistence.*; @Getter @Setter @Builder @AllArgsConstructor @NoArgsConstructor @Entity public class RequestEntity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Column(name = "user_id") private Long userId; @Column(name = "exercise_id") private Long exerciseId; @Column(name = "reps") private Integer reps; @Column(name = "weight") private Double weight; @Column(name = "date") private LocalDate date; } package org.example.persistence.entity; import lombok.*; import org.example.domain.Role; import org.hibernate.validator.constraints.Length; import javax.persistence.*; import javax.validation.constraints.NotBlank; @Entity @Data @Getter @Setter @Builder @AllArgsConstructor @NoArgsConstructor public class UserEntity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @NotBlank @Length(min = 2 ,max = 50) private String email; @NotBlank private String password; @NotBlank private String firstName; @NotBlank private String lastName; @Column(name = "role", columnDefinition = "ENUM('CUSTOMER', 'TRAINER', 'ADMINISTRATION')") @Enumerated(EnumType.STRING) private Role role; } package org.example.persistence.entity; import lombok.*; import javax.persistence.*; import java.time.LocalDate; @Entity @Data @Getter @Setter @Builder @AllArgsConstructor @NoArgsConstructor public class UserExerciseEntity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @ManyToOne @JoinColumn(name="user_id", nullable=false) private UserEntity user; @ManyToOne @JoinColumn(name="exercise_id", nullable=false) private ExerciseEntity exercise; @Column(name = "date") private LocalDate date; }
我的application.properties配置:
##spring.datasource.url=jdbc:mysql://localhost:3331/FitBuddy?useSSL=false&allowPublicKeyRetrieval=true #spring.datasource.url=jdbc:mysql://host.docker.internal:3331/FitBuddy?useSSL=false&allowPublicKeyRetrieval=true # #spring.datasource.username=root #spring.datasource.password=pass123 ### #spring.jpa.show-sql=true #spring.jpa.hibernate.ddl-auto=update #spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5Dialect #logging.level.org.hibernate.SQL=DEBUG #logging.level.org.hibernate.type.descriptor.sql.BasicBinder=TRACE #spring.jpa.open-in-view=false #jwt.secret=E91E158E4C6656F68B1B5D1C316766DE98D2AD6EF3BFB44F78E9CFCDF5 # spring.datasource.url=jdbc:mysql://localhost:3331/FitBuddy?useSSL=false&allowPublicKeyRetrieval=true #spring.datasource.url=jdbc:mysql://db:3306/FitBuddy?useSSL=false&allowPublicKeyRetrieval=true spring.datasource.username=Stoyan spring.datasource.password=pass123 spring.jpa.properties.hibernate.packagesToScan=org.example.persistence.entity spring.jpa.show-sql=true spring.jpa.hibernate.ddl-auto=update spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5Dialect logging.level.org.hibernate.SQL=DEBUG logging.level.org.hibernate.type.descriptor.sql.BasicBinder=TRACE spring.jpa.open-in-view=false jwt.secret=E91E158E4C6656F68B1B5D1C316766DE98D2AD6EF3BFB44F78E9CFCDF5
docker-compose.yml配置:
version: '3.8' services: db: image: mysql:latest ports: - 3306:3306 environment: MYSQL_DATABASE: FitBuddy MYSQL_USER: Stoyan MYSQL_PASSWORD: pass123 MYSQL_ROOT_PASSWORD: pass123 phpmyadmin: image: phpmyadmin/phpmyadmin:latest depends_on: - db environment: PMA_HOST: db ports: - 7098:80 app: build: dockerfile: Dockerfile environment: DB_HOST: db DB_PORT: 3306 DB_USER: Stoyan DB_PASSWORD: pass123 DB_NAME: FitBuddy depends_on: - db ports: - "8080:8080"
数据库连接配置不匹配
你在docker-compose中给app服务配置了DB_HOST: db等环境变量,但application.properties里硬编码了spring.datasource.url=jdbc:mysql://localhost:3331/FitBuddy——在Docker容器内,localhost指向容器自身,而不是宿主机或db容器,同时db容器的端口是3306,不是3331。这会导致应用连错数据库(甚至连不上),UserEntity的表大概率是本地开发时创建的,并非Docker环境生成。
解决:修改application.properties,用环境变量动态读取数据库配置:spring.datasource.url=jdbc:mysql://${DB_HOST}:${DB_PORT}/${DB_NAME}?useSSL=false&allowPublicKeyRetrieval=true spring.datasource.username=${DB_USER} spring.datasource.password=${DB_PASSWORD}实体扫描范围未覆盖全量实体
虽然配置了spring.jpa.properties.hibernate.packagesToScan,但Spring Boot有时更依赖@EntityScan注解来识别实体类。如果你的主应用类(带@SpringBootApplication的类)不在org.example包下,默认扫描范围不会包含org.example.persistence.entity,导致仅UserEntity被扫描到(可能是之前本地调试时的残留)。
解决:在主应用类上添加注解:@SpringBootApplication @EntityScan(basePackages = "org.example.persistence.entity") public class YourApplication { public static void main(String[] args) { SpringApplication.run(YourApplication.class, args); } }Docker容器启动顺序导致数据库未就绪
depends_on仅保证db容器先启动,但不保证MySQL服务完全初始化完成。如果应用启动时数据库还在启动过程中,Hibernate初始化会失败,无法创建所有表。
解决:- 在app服务中添加健康检查,等待MySQL就绪:
app: build: dockerfile: Dockerfile environment: DB_HOST: db DB_PORT: 3306 DB_USER: Stoyan DB_PASSWORD: pass123 DB_NAME: FitBuddy depends_on: - db ports: - "8080:8080" healthcheck: test: ["CMD-SHELL", "mysqladmin ping -h db -u Stoyan -ppass123"] interval: 10s timeout: 5s retries: 5 - 或者在应用中配置连接池重试:
spring.datasource.hikari.connection-test-query=SELECT 1 spring.datasource.hikari.maximum-pool-size=10 spring.datasource.hikari.connection-timeout=30000
- 在app服务中添加健康检查,等待MySQL就绪:
枚举类或实体关联的潜在问题
检查Role和MessageStatus枚举类的定义是否与实体中的配置一致:比如UserEntity中role的columnDefinition是ENUM('CUSTOMER', 'TRAINER', 'ADMINISTRATION'),要确保Role枚举的取值完全匹配这些字符串。另外UserExerciseEntity中的@ManyToOne关联,如果关联的实体未被扫描到,也会导致该表无法创建。
解决:核对枚举类的常量名称与实体中columnDefinition的取值完全一致,确保关联的实体类都被正确扫描。
内容的提问来源于stack exchange,提问作者SVG

