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

Spring Boot 2.7 R2DBC测试初始化H2库报SQL约束不存在错误

问题根因

你遇到的错误码90057-212是H2数据库抛出的标准语法错误,核心触发逻辑是外键引用的目标列不存在主键或唯一约束,和Spring Boot、R2DBC的上层逻辑无关,具体诱因分两类:

  • 最高发原因:account表建表语句中的id字段仅配置了自增属性,未显式声明主键约束。H2不会自动给自增列绑定主键/唯一约束,而SQL规范强制要求外键关联的目标列必须是主键或具备唯一约束,因此创建money_deposit_event表的外键时直接抛出约束不存在的异常。
  • 次要诱因:R2DBC H2驱动默认关闭多语句执行支持,如果你直接读取整个init.sql的文本内容作为单条SQL提交,会出现语句解析截断,比如account表的主键定义片段未被正确执行,最终触发相同的约束不存在错误。
修复方案

1. 修正init.sql建表语法

首先确保account表的id字段显式声明主键,参考正确写法:

-- 错误示例:仅设置自增,无主键约束
-- CREATE TABLE account (
--   id BIGINT AUTO_INCREMENT,
--   user_name VARCHAR(255),
--   balance DECIMAL(10,2)
-- );

-- 正确建表语句
CREATE TABLE account (
  id BIGINT AUTO_INCREMENT PRIMARY KEY,
  user_name VARCHAR(255) NOT NULL,
  balance DECIMAL(10,2) NOT NULL DEFAULT 0
);

CREATE TABLE money_deposit_event (
  id BIGINT AUTO_INCREMENT PRIMARY KEY,
  account_number BIGINT NOT NULL,
  amount DECIMAL(10,2) NOT NULL CHECK (amount > 99),
  CONSTRAINT fk_deposit_account FOREIGN KEY (account_number) REFERENCES account(id)
);

-- 后续插入account表初始数据的语句保持原有逻辑即可

2. 配置R2DBC多语句支持,优化初始化逻辑

在测试环境配置文件application-test.properties中添加配置,开启H2 R2DBC驱动的多语句执行能力,同时配置内存库的生命周期规则:

# H2内存库连接配置,开启多语句支持,库在JVM退出前不关闭
spring.r2dbc.url=r2dbc:h2:mem:///testdb;DB_CLOSE_DELAY=-1;MULTI_STATEMENTS=TRUE
spring.r2dbc.username=sa
spring.r2dbc.password=

如果你不想手动在@BeforeAll方法中编写脚本读取、执行逻辑,可以直接使用Spring Boot 2.7自带的R2DBC初始化能力:将init.sql重命名为schema.sql放在test资源目录下,添加如下配置即可自动完成表结构初始化,不需要自定义DatabaseClient执行逻辑:

# 开启测试环境R2DBC脚本自动初始化
spring.r2dbc.initialization-mode=always

3. 校验结果

修复后重新执行测试用例,外键约束可以正常创建,StepVerifier会正常收到onComplete()信号,不会再抛出BadSqlGrammarException。

补充排查点:如果修复后依然报错,检查init.sql中是否存在建表顺序颠倒、表名/字段名大小写不匹配的问题,H2默认对未加引号的标识符转大写,如果你在实体类中用了小写表名记得给表名、字段名加引号,或者在连接串中添加DATABASE_TO_LOWER=TRUE参数适配。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 19:03:42