You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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;
}

问题排查与解决步骤

  1. 调整Hibernate建表策略
    检查application.properties/application.yml中spring.jpa.hibernate.ddl-auto配置:

    • 临时改为create或create-drop,强制Hibernate重建所有表,启动成功后再改回update(注意create会删除原有数据,生产环境禁用)。
  2. 修复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;
    }
    
  3. 解决外键执行顺序问题
    报错原因是Hibernate先执行删除外键的DDL,此时consultation表尚未创建。解决方式:

    • 暂时删除Consultation类中@ForeignKey(name="fk_rdv_id")的显式命名,让Hibernate自动生成外键,避免提前执行删除语句。
    • 或手动在数据库创建consultation表后再启动项目。
  4. 清理缓存与重启

    • 删除数据库中残留的无效表/约束,清理Hibernate缓存。
    • 重启IDE和数据库服务,确保配置生效。

内容的提问来源于stack exchange,提问作者Hamza Erraji

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 21:25:00