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

使用H2脚本初始化Spring测试环境时插入SQL数据报主键冲突

问题:MySQL迁移H2测试环境主键冲突异常

场景还原

将MySQL初始化脚本迁移到H2内存数据库用于Spring测试,相关配置与脚本如下:

  1. src/test/resources/application.yaml配置:
spring:
    datasource:
        url: jdbc:h2:mem:bbstatstest
        username: sa
        password: sa
        driverClassName: org.h2.Driver
    jpa:
        hibernate:
            ddl-auto: none
            naming:
                physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
        open-in-view: false
        properties:
            hibernate:
                format_sql: true
        show-sql: true
    sql:
        init:
            mode: always
  1. Spring测试类代码:
@SpringBootTest
@Sql({"/schema.sql", "/data.sql"}) // 文件存放于src/test/resources目录
class BasketballStatsSpringApplicationTests {

    @Test
    void contextLoads() {
    }
}
  1. schema.sql表结构脚本:
CREATE SCHEMA IF NOT EXISTS bbstatstest;

CREATE TABLE IF NOT EXISTS bbstatstest.GeoContexts (
  id INT NOT NULL,
  parent_id INT NULL DEFAULT NULL,
  name VARCHAR(50) NOT NULL,
  type ENUM('CONTINENT', 'COUNTRY', 'REGION', 'STATE', 'DISTRICT') NULL DEFAULT NULL,
  PRIMARY KEY (id),
  CONSTRAINT geocontexts_self_fk
    FOREIGN KEY (parent_id)
    REFERENCES bbstatstest.GeoContexts (id)
    ON DELETE NO ACTION
    ON UPDATE CASCADE);
  1. data.sql数据插入脚本:
INSERT INTO bbstatstest.GeoContexts (id, parent_id, name) VALUES
(1, NULL, 'Africa'),
(2, NULL, 'Antarctica'),
(3, NULL, 'Asia'),
(4, NULL, 'Europe'),
(5, NULL, 'North America'),
(6, NULL, 'Oceania'),
(7, NULL, 'South America');

执行测试后抛出主键冲突异常:

Caused by: org.h2.jdbc.JdbcSQLIntegrityConstraintViolationException: Unique index or primary key violation: "PRIMARY KEY ON BBSTATSTEST.GEOCONTEXTS(ID) ( /* key:1 */ 1, NULL, 'Africa', NULL)"; SQL statement:
INSERT INTO bbstatstest.GeoContexts (id, parent_id, name) VALUES (1, NULL, 'Africa'), (2, NULL, 'Antarctica'), (3, NULL, 'Asia'), (4, NULL, 'Europe'), (5, NULL, 'North America'), (6, NULL, 'Oceania'), (7, NULL, 'South America') [23505-224]

问题原因

脚本被重复执行了两次:

  • spring.sql.init.mode=always配置会触发Spring Boot自动执行src/test/resources下的schema.sql和data.sql,完成数据库初始化。
  • 测试类上的@Sql注解又手动指定执行同一批脚本,导致数据插入操作被执行两次,主键1-7重复插入触发唯一约束异常。

解决方法

任选以下一种方案即可:

方案1:移除测试类上的@Sql注解

保留spring.sql.init.mode=always配置,让Spring Boot自动完成初始化,测试类简化为:

@SpringBootTest
class BasketballStatsSpringApplicationTests {

    @Test
    void contextLoads() {
    }
}

方案2:修改spring.sql.init.mode配置

将application.yaml中的spring.sql.init.mode改为never,禁用自动初始化,完全通过@Sql注解控制脚本执行:

spring:
    # 其他配置保持不变
    sql:
        init:
            mode: never

额外兼容建议(非当前报错原因)

MySQL的ENUM类型在H2中默认支持,但为了避免后续类型兼容问题,建议在H2的JDBC URL中添加MySQL兼容模式:

spring:
    datasource:
        url: jdbc:h2:mem:bbstatstest;MODE=MySQL;DATABASE_TO_LOWER=TRUE

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 12:05:31