主子表的并发控制,一般是通过主外键的约束来实现。通过这种方式,保证子表插入数据的情况下,主表不能将记录删除。
目前碰到一个问题,无法通过主外键的约束来控制并发访问。
这篇讨论目前的问题,无法使用主外键进行并发控制的情况。
无法利用主外键时控制主子表的并发访问(一):http://yangtingkun.itpub.net/post/468/453295
目前的问题是,数据库表结构采用下面的设计:
SQL> DESC T_P
名称 是否为空? 类型
-------------------- -------- ------------------------
ID NOT NULL NUMBER
FLAG VARCHAR2(1)
SQL> DESC T_F
名称 是否为空? 类型
-------------------- -------- ------------------------
ID NOT NULL NUMBER
FID NUMBER
FLAG VARCHAR2(1)
表中包含了一个FLAG标识位,而在程序进行删除操作的时候,并不是在数据库中进行产生,而是将这个FLAG状态从0置为1,表示这条记录已经删除。通过这种方式,来避免数据库中删除操作的发生。
很快就发现,这种设计将面临着一个严重的问题,就是并发控制的问题。由于数据本身并没有从数据库中删除,而只是标示位的改变,因此主外键关系一直存在,也就是说,无法通过主外键来帮助实现主子表的并发控制了。
程序员试图通过程序检查的方式来避免问题,但是这种方式是不可行的。下面通过一个例子来说明:
SQL> INSERT INTO T_P VALUES (1, 0);
已创建 1 行。
SQL> COMMIT;
提交完成。
SQL> SELECT * FROM T_P;
ID F
---------- -
1 0
下面另启动一个会话,并设置SQLPROMPT和会话一进行区别:
SQL> SET SQLP 'SQL2> '
SQL2> SELECT * FROM T_P;
ID F
---------- -
1 0
现在会话一和会话二都可以看到主记录,那么会话一尝试删除记录,也就是将FLAG表示置为1:
SQL> UPDATE T_P SET FLAG = 1 WHERE ID = 1;
已更新 1 行。
会话二尝试添加子表记录:
SQL2> INSERT INTO T_F VALUES (1, 1, 0);
已创建 1 行。
现在发现,两个操作可以同时进行,而且会话一和会话二都可以成功提交:
SQL> COMMIT;
提交完成。
会话二:
SQL2> COMMIT;
提交完成。
现在的问题时,主表记录被置于删除状态,但是子表仍然向其中插入了新的记录。这是违背业务逻辑的。
这是由于主表的记录仍然存在,因此子表的插入不会引发主外键的冲突。因此主外键对于当前设计面临逻辑业务冲突无能为力。
而程序员试图通过操作前的检查操作也是徒劳的。
插入一条新的记录:
SQL> INSERT INTO T_P VALUES (2, 0);
已创建 1 行。
SQL> COMMIT;
提交完成。
下面在会话二中尝试插入子表记录,插入之前检查主表的表示是否为0:
SQL2> SELECT * FROM T_P WHERE ID = 2;
ID F
---------- -
2 0
SQL2> INSERT INTO T_F VALUES (2, 2, 0);
已创建 1 行。
下面在会话一中尝试删除主表记录,即将标示位置为1,在删除之前检查是否存在标志位为0的记录:
SQL> SELECT * FROM T_F WHERE FID = 2 AND FLAG = 0;
未选定行
SQL> UPDATE T_P SET FLAG = 1 WHERE ID = 2;
已更新 1 行。
会话一和会话二在操作之前都进行了检查,但是他们看不到互相的操作内容,因此他们认为操作可以进行执行,而如果此时对两个会话分别提交,依然会出现主表记录被置为删除,单子表记录存在且状态不为删除的情况。
那么如果操作之前检查是行不通的,将检查放在操作之后进行,也就是说在提交之前先检查主子表的情况:
SQL> SELECT * FROM T_F WHERE FID = 2 AND FLAG = 0;
未选定行
会话二的检查:
SQL2> SELECT * FROM T_P WHERE ID = 2;
ID F
---------- -
2 0
很不幸,这种方式也是行不通的。因为Oracle中是无法看到其他会话没有提交的信息的,也就是说,会话一看不到会话二的插入,会话二也看不到会话一的修改,二者的检查结果都是没有冲突可以提交,但是提交后就会出现上面所说的违背业务逻辑的情况。
显然没有了主外键的帮助,仅靠检查是没有办法避免并发问题的,现在只能通过自己来构造这种情况下的并发控制了。
来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/4227/viewspace-162817/,如需转载,请注明出处,否则将追究法律责任。
转载于:http://blog.itpub.net/4227/viewspace-162817/