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"))); } }
异常原因分析
- Hibernate DDL执行时序冲突:Spring Boot默认通过
spring.jpa.hibernate.ddl-auto配置让Hibernate自动管理表结构。测试启动时,Hibernate会先尝试清理旧的外键约束,但此时token表可能还未创建,或在之前的测试流程中被提前删除,导致执行drop foreign key时找不到目标表。 - Cascade配置不合理:Token实体的
@ManyToOne使用了CascadeType.ALL,该配置会让Hibernate在处理关联关系时触发额外的DDL操作,加剧了表结构操作的时序问题。 - 内存数据库生命周期问题:如果使用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
相关产品推荐
相关产品推荐

