Oracle:什么时候检查约束?

Oracle: When are constraints checked?

根据我的理解,通常应在事务结束时检查约束。

因此,在一个简单的示例中,我们有一个 table A,其中唯一的列 P 是其主键,而 table B 与主键 P 和外键 FA.P 上,以下应该有效(在空 tables 上):

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 中指出(在 ACID 属性之后)

[t]he transaction takes the database from one consistent state to another consistent state.

因此可以预期两者之间的状态不一定必须一致。这当然适用于 Oracle 提供的示例:资金从一个账户转移到另一个账户,而在两者之间,资金总额不匹配(不一致),因为资金从一个账户中移除,但不是还添加到另一个。那为什么外键约束好像不一样呢?

除非您将约束明确定义为 deferred constraint,否则会在将行插入 table 时检查约束。

在提交事务之前,数据在外部实际上是不可见的,但会逐步检查数据完整性。

And if so, is there any way of enforcing this behaviour

是的,就是这样。它被称为延迟约束。

如果延迟约束,则在事务结束时检查它,而不是在执行语句时检查。

alter table some_table
   add constraint fk_something 
   foreign key (some_column) references other_table(pk_column)
   deferrable initially deferred;

有关 initially deferredinitially immediate

之间区别的解释,请参阅 this answer

解决此问题的一种方法是 延迟 块内的相关约束,例如:

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;