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

Spring Boot 3测试时DDL执行异常:token表不存在问题排查

问题:Spring Boot 3测试用例通过但抛出DDL执行异常

在Spring Boot 3项目中,定义了user和token两张关联表,实体类代码如下:

User 实体类

@Setter
@Getter
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Entity
@Table(name = "user")
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(name = "username", unique = true, nullable = false)
    private String username;

    @Column(name = "password", nullable = false)
    private String password;

    @Column(name = "full_name")
    private String fullName;

    @Column(name = "created_at", updatable = false)
    private LocalDateTime createdAt;

    @Column(name = "updated_at", insertable = false)
    private LocalDateTime updatedAt;

    @OneToMany(mappedBy = "user")
    private List<Token> tokens;
}

Token 实体类

@Builder
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Getter
@Setter
@Table(name = "token")
public class Token {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(unique = true)
    private String token;

    @Column(name = "expired")
    private boolean expired;

    @ManyToOne(fetch = FetchType.LAZY, cascade = {CascadeType.ALL})
    @JoinColumn(name = "user_id")
    private User user;
}

运行DemoControllerTest测试用例时,所有用例均通过,但控制台抛出如下异常:

org.hibernate.tool.schema.spi.CommandAcceptanceException: Error executing DDL "alter table token drop foreign key FKe32ek7ixanakfqsdaokm4q9y2" via JDBC [Table 'test.token' doesn't exist]

测试类代码:

@SpringBootTest
@AutoConfigureMockMvc
public class DemoControllerTest {
    @Autowired
    private DemoController demoController;

    @Autowired
    private MockMvc mockMvc;

    @Test
    void demoControllerInitializedCorrectly() {
        assertThat(demoController).isNotNull();
    }

    @Test
    void testReturn200() throws Exception {
        mockMvc.perform(get("/api/v1/demo")).andExpect(status().isOk());
    }

    @Test
    void testReturnDemoMessage() throws Exception {
        mockMvc.perform(get("/api/v1/demo")).andExpect(content().string(containsString("API demo is running")));
    }
}

异常原因分析

  1. Hibernate DDL执行时序冲突:Spring Boot默认通过spring.jpa.hibernate.ddl-auto配置让Hibernate自动管理表结构。测试启动时,Hibernate会先尝试清理旧的外键约束,但此时token表可能还未创建,或在之前的测试流程中被提前删除,导致执行drop foreign key时找不到目标表。
  2. Cascade配置不合理:Token实体的@ManyToOne使用了CascadeType.ALL,该配置会让Hibernate在处理关联关系时触发额外的DDL操作,加剧了表结构操作的时序问题。
  3. 内存数据库生命周期问题:如果使用H2这类内存数据库,测试结束后数据库会被销毁,但Hibernate下次启动时仍会基于历史元数据执行清理操作,从而引发找不到表的错误。

解决方法

方法1:调整Hibernate DDL配置

修改测试环境配置文件(如application-test.properties)中的DDL自动管理策略,避免不必要的清理操作:

# 测试环境推荐使用create-drop,启动时创建表,关闭时自动删除
spring.jpa.hibernate.ddl-auto=create-drop

# 若不需要自动生成表,可设置为none
# spring.jpa.hibernate.ddl-auto=none

方法2:修正CascadeType配置

Token实体的@ManyToOne无需CascadeType.ALL,可根据业务需求调整为更合理的级联类型,或直接移除级联配置:

// 仅级联持久化操作
@ManyToOne(fetch = FetchType.LAZY, cascade = {CascadeType.PERSIST})
@JoinColumn(name = "user_id")
private User user;

// 或完全移除级联配置
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id")
private User user;

方法3:控制测试事务生命周期

在测试类上添加@Transactional和@Rollback注解,保证每个测试结束后回滚事务,避免表结构被提前删除:

@SpringBootTest
@AutoConfigureMockMvc
@Transactional
@Rollback
public class DemoControllerTest {
    // 测试代码保持不变
}

内容的提问来源于stack exchange,提问作者Huy Vu The

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 14:32:29