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
相关产品推荐
相关产品推荐

