向H2内存库插入数据时触发ID主键约束冲突问题求助
H2内存数据库主键约束冲突问题分析
是的,"PRIMARY KEY ON MY_TABLE(ID)"明确表示这是主键ID的约束冲突,错误代码23505是SQL标准中定义的唯一约束/主键冲突错误码,和表中其他唯一约束无关。
问题根源
你使用的BIGSERIAL是H2的自增主键类型,它依赖内置序列自动生成ID。当你手动指定ID值插入数据时(比如最小示例中的INSERT INTO MY_TABLE(ID, VAL) VALUES (2, 99);),H2不会自动更新序列的计数器。后续用default插入时,序列仍会从初始值(通常为1)开始生成,当生成的ID与之前手动插入的ID重复时,就会触发主键冲突。
测试场景的触发原因
你的测试套件中应该存在某个测试手动指定了ID插入数据,后续测试未重置数据库状态(比如未重建表、未重置序列),导致自增生成的ID与已存在的ID重复,即使测试串行执行也会出现该问题。
最小复现示例
-- 创建表 CREATE TABLE MY_TABLE ( id BIGSERIAL PRIMARY KEY, val BIGINT NOT NULL ); -- 手动指定ID插入 INSERT INTO MY_TABLE(ID, VAL) VALUES (2, 99); -- 使用自增插入,第三次插入时会触发主键冲突 INSERT INTO MY_TABLE(ID, VAL) VALUES (default, 99); INSERT INTO MY_TABLE(ID, VAL) VALUES (default, 99); INSERT INTO MY_TABLE(ID, VAL) VALUES (default, 99);
解决方法
- 统一使用
default让数据库自动生成主键ID,避免手动指定ID值。 - 若必须手动插入ID,插入后需手动更新序列,确保后续自增ID不重复:
ALTER SEQUENCE MY_TABLE_ID_SEQ RESTART WITH (SELECT MAX(ID) + 1 FROM MY_TABLE);
- 测试场景下,每个测试用例执行前重置数据库状态(如重建表、清空表并重置序列),避免测试间状态污染。
内容的提问来源于stack exchange,提问作者talex
相关产品推荐
相关产品推荐

