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

Spring Test或JUnit是否执行隐式清理?重复插入主键未报错存疑

重复插入同主键数据未抛出异常的原因

问题场景

编写的测试代码如下:

@DataJpaTest
@ActiveProfiles("test")
@Sql(
        executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD,
        scripts = {"/create_user_table.sql", "/insert_user.sql"}
)
public class H2DemoApplicationTest {
    @Test
    void testNothing() {
    }

    @Test
    void testNothingOneMoreTime() {
    }
}

对应的SQL脚本:
create_user_table.sql

-- create_user_table.sql

CREATE TABLE IF NOT EXISTS users(
  id INTEGER PRIMARY KEY,
  name VARCHAR(50) NOT NULL,
  last_name VARCHAR(50)
);

insert_user.sql

-- insert_user.sql

INSERT INTO users
VALUES (1, 'John', 'Doe');

测试配置:

# knocked myself out. gimme all them logs!! i don't care about all your properties, spring

spring.jpa.properties.hibernate.show_sql=true
spring.jpa.properties.hibernate.use_sql_comments=true
spring.jpa.properties.hibernate.format_sql=true
logging.level.org.hibernate.type=trace

logging.level.org.springframework.jdbc.core=TRACE
logging.level.org.springframework.jdbc.datasource.init=DEBUG
logging.level.org.springframework.test.context.jdbc=DEBUG

未手动执行任何清理操作,按预期第二次测试前插入相同主键的数据应抛出异常,但实际执行正常,控制台日志显示两次插入均成功,想确认Spring Test(或JUnit)是否执行了隐式清理。

核心原因

这是因为@DataJpaTest注解默认会为每个测试方法启动一个独立的事务,并且在测试方法执行完毕后自动回滚事务。

  • 第一个测试方法执行时,@Sql脚本创建表并插入数据的操作都在当前事务内,测试结束后事务回滚,数据库会恢复到执行脚本前的状态。
  • 第二个测试方法执行时,相当于在一个全新的数据库环境下再次执行脚本:CREATE TABLE IF NOT EXISTS会重新创建表(因为之前的表已经随事务回滚消失),插入同主键的数据自然不会触发主键冲突。

如果想禁用这种默认的回滚行为,可以在测试类或单个测试方法上添加@Rollback(false)注解,此时第二次测试就会因为主键重复抛出异常。

内容的提问来源于stack exchange,提问作者Sergey Zolotarev

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 19:47:19