Spring Boot+Gradle+H2测试报错:主键/唯一索引冲突求助
主键冲突问题排查与解决
以下是针对你遇到的主键冲突问题的具体排查方向和解决办法:
1. 避免data.sql重复执行
@DataJpaTest注解默认会自动加载并执行src/test/resources下的schema.sql和data.sql脚本,而你又通过@Sql注解显式引入了data.sql,这会导致脚本被执行两次,直接触发主键重复插入的错误。
- 解决方式:
- 移除测试类上的
@Sql注解,依赖@DataJpaTest的自动初始化逻辑; - 或者在测试配置文件(如
application-test.properties)中禁用自动数据初始化:
保留spring.sql.init.mode=never@Sql注解来手动控制脚本执行时机。
- 移除测试类上的
2. 对齐主键生成策略与插入数据
如果你的Product实体类中ID_PRODUCT字段使用了自增主键策略(比如@GeneratedValue(strategy = GenerationType.IDENTITY)),H2数据库的自增序列可能已经有初始值,和你data.sql中手动插入的ID值冲突。
- 解决方式:
- 在
data.sql末尾添加重置序列的语句,确保自增起始值大于你插入的最大ID:ALTER SEQUENCE product_id_product_seq RESTART WITH 3; - 或者修改
data.sql中的插入ID,避开自增序列的默认起始范围。
- 在
3. 隔离测试上下文,防止数据残留
Spring Boot测试默认会复用应用上下文,如果有其他测试类也操作了product表,可能导致数据残留到当前测试中,引发主键冲突。
- 解决方式:
在测试类上添加@DirtiesContext注解,确保每个测试方法执行后重置上下文:@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD) @DataJpaTest @Sql("classpath:data.sql") public class ClientRepositoryTest { // 测试代码 }
4. 确认Schema与表名匹配
你在data.sql中使用了public.product的全限定表名,但H2数据库默认的Schema可能不是public,或者测试环境的JPA配置指定了其他Schema,导致实际插入的表和实体映射的表不一致,但主键序列共用引发冲突。
- 解决方式:
- 检查测试配置中的
spring.jpa.properties.hibernate.default_schema是否设置为public; - 或者将
data.sql中的表名简化为product,去掉Schema前缀。
- 检查测试配置中的
5. 直观验证H2数据库状态
开启H2控制台,直接查看测试执行前后product表的数据,就能明确数据来源:
- 在
application-test.properties中添加配置:spring.h2.console.enabled=true spring.h2.console.path=/h2-console - 启动测试后,访问
http://localhost:8080/h2-console,使用测试环境的H2连接参数登录,查看product表的初始数据和插入记录,定位重复插入的原因。
内容的提问来源于stack exchange,提问作者racso
相关产品推荐
相关产品推荐

