据我所知,通常应在交易结束时检查约束。
因此,在一个简单的示例中,我们有一个具有唯一列A
的表P
,这是它的主键,还有一个具有主键B
和外键P
的表F
在A.P
上,以下内容应该起作用(在空表上):
begin
insert into B (P, F)
values (1, 1);
insert into A (P)
values (1);
commit;
end;
但是,Oracle给了我错误(德语):
[23000][2291] ORA-02291: Integritäts-Constraint (DATABASE.AB_constraint) verletzt - übergeordneter Schlüssel nicht gefunden
ORA-06512: in Zeile 3
Position: 0
翻译为违反完整性约束-找不到引用的键。如果我撤消命令
begin
insert into A (P)
values (1);
insert into B (P, F)
values (1, 1);
commit;
end;
效果很好。在Oracle事务结束时是否未验证约束?如果是这样,是否有任何方法可以强制执行此行为?
在Oracle docs中声明(遵循A C ID属性)
[t]该事务将数据库从一个一致状态转移到另一一致状态。
因此,可以期望介于两者之间的状态不必一定保持一致。这当然适用于Oracle提供的示例:钱从一个帐户转移到另一个帐户,而在这两者之间,总金额不匹配(不一致),因为从一个帐户中取出了钱,但不尚未添加到另一个。那么为什么外键约束看起来不一样?
如果是,是否有任何方法可以强制执行此行为
是,是的。这称为延迟约束。
如果延迟约束,则在事务结束时检查约束,而不是在执行语句时检查约束。
alter table some_table
add constraint fk_something
foreign key (some_column) references other_table(pk_column)
deferrable initially deferred;
关于this answer和initially deferred
之间的区别的说明,请参见initially immediate
解决此问题的一种方法是defer块内的相关约束,例如:
begin
execute immediate 'set constraint ab_constraint deferred';
insert into B (P, F) values (1, 1);
insert into A (P) values (1);
execute immediate 'set constraint ab_constraint immediate';
commit;
end;
除非您将约束明确定义为deferred constraint,否则将在将行插入表中时检查约束。
在提交事务之前,实际上在外部看不到数据,但是逐步检查了数据完整性。