在集群模式下添加子行 table 时违反 H2 引用完整性
H2 Referential Integrity violation when adding row of a child table in cluster mode
TL; DR: 未发生违规时触发引用完整性违规。
我 运行 H2 在集群模式下有 2 个节点。
我在 H2 数据库 (v1.4.189) 中有两个 tables,一个父项和一个子项。子项包含指向父项 table 行的 ID 的外键。
通常,在子 table.
中插入一行时,我不会收到任何错误
但是过了一会儿,我在插入时遇到了这个错误:
Referential integrity constraint violation: "CONSTRAINT_1FE: PUBLIC.CHILD FOREIGN KEY(fkey)
REFERENCES PUBLIC.PARENT(ID) (86)"
奇怪的是,产生错误的INSERT INTO数据插入成功,而且没有违反外键约束!
我已尝试记录重现错误的确切步骤,但使用新数据库时,错误永远不会发生:
drop table CHILD;
drop table PARENT;
create table CHILD(id int auto_increment, name varchar(255), fkey int);
create table PARENT(id int auto_increment, name varchar(255));
ALTER TABLE `CHILD` ADD FOREIGN KEY (fkey) REFERENCES `PARENT` (`id`);
insert into PARENT(name) values('hello');
insert into PARENT(name) values('world');
select * from PARENT;
insert into CHILD(name, fkey) values('hello', 1);
-- this works for a while, but someday the Referential integrity error
-- will pop, but data will be added anyway (wtf?)
insert into CHILD(name, fkey) values('world', 2);
在数据库上,我只是做一些简单的事情,比如选择、插入、删除...
有趣的是,在这个错误发生一次之后,我又遇到了另一个奇怪的错误:删除(或更新)CHILD table 的行时,DELETE FROM 或 UPDATE 函数总是 return 0,即使某些行已被删除...(也 jdbc executeUpdate() 总是 returns 0)
数据库是否在某个时候损坏了?
我发现修复此错误的唯一解决方法是删除所有 table 并重新创建 table,这不是我想要做的。
H2 主要开发者 thomas mueller 在 github 上回答了这个问题:
This is one of the documented limitations of the cluster feature, see
also "Clustering Algorithm and Limitations": "Using auto-increment and
identity columns is currently not supported."
I'm afraid it's hard to fix it. I suggest to not use the cluster
feature for this reason. Support for it will probably be removed in
the future. I hope a new cluster / automatic failover feature can be
added, but this will take some time.
But this might be interesting for you: https://github.com/shesse/h2ha
我设法让它工作:使用序列并插入两次:
- 获取此 table 序列的 nextval,例如:nextid =select childsequence.nextval from dual
- 然后做你的 INSERT INTO child
并指定 id nextid
未找到外键导致异常,需要先插入依赖数据
示例:
// Execute below query first
INSERT INTO root_table VALUES (value1, value2)
// Execute below query after root_table
INSERT INTO sub_Table VALUES (value1, value2, FK_root_ID)
TL; DR: 未发生违规时触发引用完整性违规。
我 运行 H2 在集群模式下有 2 个节点。
我在 H2 数据库 (v1.4.189) 中有两个 tables,一个父项和一个子项。子项包含指向父项 table 行的 ID 的外键。
通常,在子 table.
中插入一行时,我不会收到任何错误
但是过了一会儿,我在插入时遇到了这个错误:
Referential integrity constraint violation: "CONSTRAINT_1FE: PUBLIC.CHILD FOREIGN KEY(fkey)
REFERENCES PUBLIC.PARENT(ID) (86)"
奇怪的是,产生错误的INSERT INTO数据插入成功,而且没有违反外键约束!
我已尝试记录重现错误的确切步骤,但使用新数据库时,错误永远不会发生:
drop table CHILD;
drop table PARENT;
create table CHILD(id int auto_increment, name varchar(255), fkey int);
create table PARENT(id int auto_increment, name varchar(255));
ALTER TABLE `CHILD` ADD FOREIGN KEY (fkey) REFERENCES `PARENT` (`id`);
insert into PARENT(name) values('hello');
insert into PARENT(name) values('world');
select * from PARENT;
insert into CHILD(name, fkey) values('hello', 1);
-- this works for a while, but someday the Referential integrity error
-- will pop, but data will be added anyway (wtf?)
insert into CHILD(name, fkey) values('world', 2);
在数据库上,我只是做一些简单的事情,比如选择、插入、删除...
有趣的是,在这个错误发生一次之后,我又遇到了另一个奇怪的错误:删除(或更新)CHILD table 的行时,DELETE FROM 或 UPDATE 函数总是 return 0,即使某些行已被删除...(也 jdbc executeUpdate() 总是 returns 0)
数据库是否在某个时候损坏了?
我发现修复此错误的唯一解决方法是删除所有 table 并重新创建 table,这不是我想要做的。
H2 主要开发者 thomas mueller 在 github 上回答了这个问题:
This is one of the documented limitations of the cluster feature, see also "Clustering Algorithm and Limitations": "Using auto-increment and identity columns is currently not supported."
I'm afraid it's hard to fix it. I suggest to not use the cluster feature for this reason. Support for it will probably be removed in the future. I hope a new cluster / automatic failover feature can be added, but this will take some time.
But this might be interesting for you: https://github.com/shesse/h2ha
我设法让它工作:使用序列并插入两次:
- 获取此 table 序列的 nextval,例如:nextid =select childsequence.nextval from dual
- 然后做你的 INSERT INTO child
并指定 id nextid
未找到外键导致异常,需要先插入依赖数据
示例:
// Execute below query first
INSERT INTO root_table VALUES (value1, value2)
// Execute below query after root_table
INSERT INTO sub_Table VALUES (value1, value2, FK_root_ID)