oracle事务_笔记5:IMMEDIATE约束
IMMEDIATE约束
我们假设约束都是IMMEDIATE模式,在这种情况下,完整性约束会在整个SQL语句得到处理之后立即检查。如果一个PL/SQL存储过程中有多条SQL语句,那么在每条SQL语句执行之后都会立即验证其完整性约束,而不是在这个存储过程完成后才检查它。
为什么约束要在SQL语句执行之后才验证呢?为什么不是在SQL语句执行期间验证?这是因为,一条语句可能会使表中的各行暂时“不一致”,这是很自然的。尽管一条语句全部完成后的最终结果是对的,但如果查看这条语句所做的部分工作,会导致Oracle拒绝这个结果
scott@ORCL>create table t (x int unique);
Table created.
scott@ORCL>insert into t values(1);
1 row created.
scott@ORCL>insert into t values(2);
1 row created.
scott@ORCL>commit;
Commit complete.
scott@ORCL>update t set x=x-1;
2 rows updated.
如果Oracle每更新一行之后都检查约束,那么无论什么时候,UPDATE都有一半的可能性会失败。由于会以某种顺序来访问T中的行,如果Oracle先更新X=1这一行,那么X暂时会有一个重复的值,这就会拒绝UPDATE。由于Oracle会耐心地等待语句结束(而不是在语句执行期间检查约束),所以这条语句最后会成功,因为等到语句完成时,已经不存在重复值了。
???8.4.2DEFERRABLE约束和级联更新
从Oracle8.0开始,我们还能够延迟约束检查。对于许多操作来说,这很有好处。首先能想到的是,可能需要将一个主键的UPDATE级联到子键。有了可延迟的结束,就使得级联更新成为可能。
在以前的版本中,确实也可以完成CASCADE UPDATE,但是为此需要做大量的工作,而且存在某些限制。有了可延迟的约束后,这就变得易如反掌了。
scott@ORCL>create table child
2 (fk constraint child_fk_parent
3 references parent(pk)
4 deferrable
5 initially immediate
6 )
7 /
Table created.
scott@ORCL>insert into parent values(1);
1 row created.
scott@ORCL>insert into child values(1);
1 row created.
我们有一个父表PARENT,还有一个子表CHILD。表CHILD引用了表PARENT,保证这个规则的约束是CHILD_FK_PARENT(到父表子外键)。这个约束创建为一个DEFERRABLE约束,但是设置为INITIALLY IMMEDIATE。这说明,可以把这个约束延迟到COMMIT或另外某个时间才检查。不过,默认情况下,这个约束会在语句级验证。
scott@ORCL>update parent set pk=2;
update parent set pk=2
*
ERROR at line 1:
ORA-02292: integrity constraint (SCOTT.CHILD_FK_PARENT) violated - child record found
由于约束是IMMEDIATE模式,这个UPDATE会失败。下面换个模式再试一次:
scott@ORCL>set constraint child_fk_parent deferred;
Constraint set.
scott@ORCL>update parent set pk=2;
1 row updated.
现在更新成功了。为了便于说明,下面将显示如何在提交前显式地检查一个延迟结束,从中了解我们所做的修改与业务规则是否一致。(换句话说,检查目前确实没有违反约束。)应该在提交之前或者在把控制交给程序的另外某个部分(这一部分可能不希望有延迟约束)之前做这个工作,这是一个很好的方法:
scott@ORCL>set constraint child_fk_parent immediate;
set constraint child_fk_parent immediate
*
ERROR at line 1:
ORA-02291: integrity constraint (SCOTT.CHILD_FK_PARENT) violated - parent key not found
不出所料,它会失败,并立即返回一个错误,因为我们知道以上更新会违反约束。对PARENT的UPDATE没有回滚(否则会违反语句级原子性),它仍在进行。还要注意,我们的事务仍把CHILD_FK_PARENT当做延迟约束,因为SET CONSTRAINT命令失败了。下面继续将UPDATE级联到CHILD:
scott@ORCL>update child set fk=2;
1 row updated.
scott@ORCL>set constraint child_fk_parent immediate;
Constraint set.
scott@ORCL>commit;
Commit complete.
这就是级联更新的做法。注意,要延迟一个约束,必须这样来创建它们:先将其删除,再重新创建约束,这样才能把不可延迟的约束改变为可延迟约束。
本文来源 我爱IT技术网 http://www.52ij.com/jishu/5239.html 转载请保留链接。
- 评论列表(网友评论仅供网友表达个人看法,并不表明本站同意其观点或证实其描述)
-
