Spring Boot预约管理项目DDL执行错误,Doctor/Patient表未创建
问题分析与解决方案
问题概述
基于Spring Boot开发的「预约管理」项目启动时,服务器能正常启动,但控制台抛出DDL执行错误:数据库中Doctor和Patient表未生成,且执行alter table consultation drop foreign key fk_rdv_id语句失败,根源是projet数据库中不存在consultation表。项目采用单表继承模式,抽象类User派生出Doctor和Patient,同时包含Rdv(预约)、Consultation(会诊)实体类,疑似实体类变更导致问题,但无法定位具体点。
错误栈信息
org.hibernate.tool.schema.spi.CommandAcceptanceException: Error executing DDL "alter table consultation drop foreign key fk_rdv_id" via JDBC Statement at org.hibernate.tool.schema.internal.exec.GenerationTargetToDatabase.accept(GenerationTargetToDatabase.java:67) ~[hibernate-core-6.1.7.Final.jar:6.1.7.Final] ...(省略中间栈信息) Caused by: java.sql.SQLSyntaxErrorException: Table 'projet.consultation' doesn't exist at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:120) ~[mysql-connector-j-8.0.32.jar:8.0.32] ...
相关实体类代码
抽象类User
package com.rdv.gestionrdvs.entities; import jakarta.persistence.*; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import org.springframework.security.core.userdetails.UserDetails; @Entity @Data @NoArgsConstructor @AllArgsConstructor @Inheritance(strategy = InheritanceType.SINGLE_TABLE) @DiscriminatorColumn(name = "TYPE", discriminatorType = DiscriminatorType.STRING ) public abstract class User implements UserDetails { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Column(length = 40) private String name; @Column( length = 200) private String password; @Column(unique = true, length = 40 ) private String email; private int phone_number; @Enumerated(EnumType.STRING) private Role role; }
Patient类
package com.rdv.gestionrdvs.entities; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import jakarta.persistence.*; import lombok.Data; import lombok.NoArgsConstructor; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; import java.util.ArrayList; import java.util.Collection; import java.util.List; @Entity @NoArgsConstructor @DiscriminatorValue("patient") public class Patient extends User{ public Patient( Long id, String name, String password, String email, int phone_number) { super(id , name, password, email, phone_number, Role.PATIENT); } @OneToMany(mappedBy = "patient" , fetch = FetchType.EAGER , cascade = CascadeType.ALL) @JsonIgnoreProperties("patient") private final List<Rdv> rdv= new ArrayList<>(); @Override public Collection<? extends GrantedAuthority> getAuthorities() { return List.of(new SimpleGrantedAuthority(Role.PATIENT.name())); } @Override public String getUsername() { return this.getEmail(); } @Override public boolean isAccountNonExpired() { return true; } @Override public boolean isAccountNonLocked() { return true; } @Override public boolean isCredentialsNonExpired() { return true; } @Override public boolean isEnabled() { return true; } }
Doctor类
package com.rdv.gestionrdvs.entities; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import jakarta.persistence.*; import lombok.NoArgsConstructor; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; import java.util.ArrayList; import java.util.Collection; import java.util.List; @Entity @DiscriminatorValue("doctor") public class Doctor extends User{ private String speciality; public Doctor( Long id, String name, String password, String email, int phone_number , String specialty ) { super(id , name, password, email, phone_number,Role.DOCTOR); this.speciality= specialty; } public String getSpeciality() { return speciality; } public void setSpeciality(String speciality) { this.speciality = speciality; } public List<Rdv> getRdv() { return rdv; } @OneToMany(mappedBy = "doctor" , fetch = FetchType.EAGER, cascade = CascadeType.ALL) @JsonIgnoreProperties("doctor") private final List<Rdv> rdv= new ArrayList<>(); @Override public Collection<? extends GrantedAuthority> getAuthorities() { return List.of(new SimpleGrantedAuthority(Role.DOCTOR.name())); } @Override public String getUsername() { return getEmail(); } @Override public boolean isAccountNonExpired() { return true; } @Override public boolean isAccountNonLocked() { return true; } @Override public boolean isCredentialsNonExpired() { return true; } @Override public boolean isEnabled() { return true; } }
Rdv类
package com.rdv.gestionrdvs.entities; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import jakarta.persistence.*; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import java.time.LocalDateTime; @Entity @Data @AllArgsConstructor @NoArgsConstructor public class Rdv { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long rdv_id; private LocalDateTime date_rdv; private Boolean isCanceld; @ManyToOne(cascade = CascadeType.ALL) @JoinColumn( foreignKey = @ForeignKey(name = "fk_doctor_id")) @JsonIgnoreProperties("rdv") private Doctor doctor; @ManyToOne(cascade = CascadeType.ALL) @JoinColumn( foreignKey = @ForeignKey(name= "fk_patient_id")) @JsonIgnoreProperties("rdv") private Patient patient; // @OneToOne // @JoinColumn(name = "consultation-id") // private Consultation consultation; }
Consultation类
package com.rdv.gestionrdvs.entities; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import jakarta.persistence.*; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @Entity @Data @AllArgsConstructor @NoArgsConstructor public class Consultation { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long consultation_id; private String diagnostic; @OneToOne(cascade = CascadeType.ALL , fetch = FetchType.EAGER) @JoinColumn( foreignKey = @ForeignKey(name="fk_rdv_id") ,referencedColumnName = "rdv_id") @JsonIgnoreProperties("consultation") private Rdv rdv; }
问题排查与解决步骤
调整Hibernate建表策略
检查application.properties/application.yml中spring.jpa.hibernate.ddl-auto配置:- 临时改为
create或create-drop,强制Hibernate重建所有表,启动成功后再改回update(注意create会删除原有数据,生产环境禁用)。
- 临时改为
修复Doctor类映射顺序错误
Doctor类中getRdv()方法定义在rdv字段之前,导致Hibernate映射异常。调整顺序:// 先定义字段,再写get方法 @OneToMany(mappedBy = "doctor" , fetch = FetchType.EAGER, cascade = CascadeType.ALL) @JsonIgnoreProperties("doctor") private final List<Rdv> rdv= new ArrayList<>(); public List<Rdv> getRdv() { return rdv; }解决外键执行顺序问题
报错原因是Hibernate先执行删除外键的DDL,此时consultation表尚未创建。解决方式:- 暂时删除
Consultation类中@ForeignKey(name="fk_rdv_id")的显式命名,让Hibernate自动生成外键,避免提前执行删除语句。 - 或手动在数据库创建
consultation表后再启动项目。
- 暂时删除
清理缓存与重启
- 删除数据库中残留的无效表/约束,清理Hibernate缓存。
- 重启IDE和数据库服务,确保配置生效。
内容的提问来源于stack exchange,提问作者Hamza Erraji
相关产品推荐
相关产品推荐

