主子表的并发控制,一般是通过主外键的约束来实现。通过这种方式,保证子表插入数据的情况下,主表不能将记录删除。
目前碰到一个问题,无法通过主外键的约束来控制并发访问。
这篇讨论主外键是如何控制主子表的并发访问的。
构造一个简单的例子,来说明主外键对并发的控制:
SQL> CREATE TABLE T_P (ID NUMBER PRIMARY KEY, FLAG VARCHAR2(1));
表已创建。
SQL> CREATE TABLE T_F
2 (
3 ID NUMBER PRIMARY KEY,
4 FID NUMBER,
5 FLAG VARCHAR2(1),
6 FOREIGN KEY (FID) REFERENCES T_P
7 );
表已创建。
SQL> INSERT INTO T_P VALUES (1, 0);
已创建 1 行。
SQL> COMMIT;
提交完成。
SQL> SELECT * FROM T_P;
ID F
---------- -
1 0
现在新启动一个SQLPLUS,设置不同的SQLPROMPT,和会话一以示区别:
SQL> SET SQLP 'SQL2> '
SQL2> SELECT * FROM T_P;
ID F
---------- -
1 0
现在在会话一对主表记录进行删除:
SQL> DELETE T_P WHERE ID = 1;
已删除 1 行。
在会话二对子表进行插入,引用会话一要删除的主表记录:
SQL2> INSERT INTO T_F VALUES (1, 1, 0);
会话二这时被锁住:
SQL> ROLLBACK;
回退已完成。
会话一回滚后,会话二插入成功:
已创建 1 行。
SQL2> ROLLBACK;
回退已完成。
SQL2> SELECT * FROM T_F;
未选定行
SQL2> SELECT * FROM T_P;
ID F
---------- -
1 0
回到开始的状态,先删除主表:
SQL> DELETE T_P WHERE ID = 1;
已删除 1 行。
在会话二插入参考删除主表记录的子表记录:
SQL2> INSERT INTO T_F VALUES (1, 1, 0);
会话二处于被锁的状态,如果这时会话一提交:
SQL> COMMIT;
提交完成。
则会话二插入报错,主键不存在:
INSERT INTO T_F VALUES (1, 1, 0)
*
第 1 行出现错误:
ORA-02291: 违反完整约束条件 (TEST.SYS_C0012880) - 未找到父项关键字
SQL2>
Oracle正是通过主外键的关系实现了主子表的并发控制,确保表的数据不会出现子表记录被插入但是对应的主表信息被删除的情况。
上面是对先删除主表记录的情况进行的分析,如果先插入子表的记录,而后进行主表记录的删除,那么情况和上面没有什么区别,都是后面的事务等待前一个事务的提交和回滚。下面通过例子简单描述一下:
SQL> INSERT INTO T_P VALUES (1, 0);
已创建 1 行。
SQL> COMMIT;
提交完成。
SQL> SELECT * FROM T_P;
ID F
---------- -
1 0
SQL> INSERT INTO T_F VALUES (1, 1, 0);
已创建 1 行。
会话二的删除会被锁:
SQL2> SELECT * FROM T_P;
ID F
---------- -
1 0
SQL2> DELETE T_P WHERE ID = 1;
会话一提交:
SQL> COMMIT;
提交完成。
会话二则报错:
DELETE T_P WHERE ID = 1
*
第 1 行出现错误:
ORA-02292: 违反完整约束条件 (TEST.SYS_C0012880) - 已找到子记录
SQL2>
正常情况下,Oracle的主外键可以帮助我们在并发访问的情况下来维护数据的完整性。
来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/4227/viewspace-162807/,如需转载,请注明出处,否则将追究法律责任。
转载于:http://blog.itpub.net/4227/viewspace-162807/