ITPub博客

首页 > Linux操作系统 > Linux操作系统 > 无法利用主外键时控制主子表的并发访问(三)

无法利用主外键时控制主子表的并发访问(三)

原创 Linux操作系统 作者:yangtingkun 时间:2008-01-28 17:48:49 0 删除 编辑

主子表的并发控制,一般是通过主外键的约束来实现。通过这种方式,保证子表插入数据的情况下,主表不能将记录删除。

目前碰到一个问题,无法通过主外键的约束来控制并发访问。

这篇描述无法利用主外键时,如何进行并发控制。

无法利用主外键时控制主子表的并发访问(一):http://yangtingkun.itpub.net/post/468/453295

无法利用主外键时控制主子表的并发访问(二):http://yangtingkun.itpub.net/post/468/453397

 

 

仍然是下面的表结构:

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> INSERT INTO T_P VALUES (2, 0);

已创建 1 行。

SQL> COMMIT;

提交完成。

会话二设置SQLPROMPT来区别会话一:

SQL> SET SQLP 'SQL2> '
SQL2> SELECT * FROM T_P;

        ID F
---------- -
         1 0
         2 0

下面会话一修改主表的删除标识:

SQL> UPDATE T_P SET FLAG = 1 WHERE ID = 1 AND FLAG = 0;

已更新 1 行。

SQL> UPDATE T_F SET FLAG = 1 WHERE FID = 1 AND FLAG = 0;

已更新0行。

为了在主表资源上获取锁,因此先更新主表记录,在更新完主表记录后,在更新子表记录。

此时会话二要添加子表的记录,为了保证并发性,避免主表在更新子表的过程中被修改,会话二也需要先获取主表上的锁:

SQL2> SELECT * FROM T_P WHERE ID = 1 AND FLAG = 0 FOR UPDATE;

子表执行完操作后被锁定,只有主表提交或回滚才能继续执行。如果这个时候会话一回滚,那么就相当于没有会话一没有操作,当前会话可以顺利的获取主表上的锁,并插入记录。如果这个时候会话一提交:

SQL> COMMIT;

提交完成。

那么会话二将无法获取到锁资源:


未选定行

SQL2>

这个时候,会话二就不能在继续执行下面的操作了,从而避免了并发修改造成的错误。下面看看先执行插入的情况:

SQL> SELECT * FROM T_P WHERE ID = 2 AND FLAG = 0 FOR UPDATE;

        ID F
---------- -
         2 0

SQL> INSERT INTO T_F VALUES (2, 2, 0);

已创建 1 行。

这个时候在会话二尝试更新主表的删除表示位:

SQL2> UPDATE T_P SET FLAG = 1 WHERE ID = 2 AND FLAG = 0;

会话二会被锁住。如果会话一回滚,则会话二获得主表的锁,并继续更新。如果会话一提交:

SQL> COMMIT;

提交完成。

则会话二同样可以获取到锁的资源,而且继续更新子表记录,并不会造成主表记录被标识为删除,而子表记录没有被标识的情况:

SQL2> UPDATE T_P SET FLAG = 1 WHERE ID = 2 AND FLAG = 0;

已更新 1 行。

SQL2> UPDATE T_F SET FLAG = 1 WHERE FID = 2 AND FLAG = 0;

已更新 1 行。

SQL2> COMMIT;

提交完成。

通过这种方式,可以保证在并发修改下,主表记录和子表的记录的一致性状态。

SQL> SELECT * FROM T_P;

        ID F
---------- -
         1 1
         2 1

SQL> SELECT * FROM T_F;

        ID        FID F
---------- ---------- -
         2          2 1

 

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/4227/viewspace-163523/,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论
暂无介绍

注册时间:2007-12-29

  • 博文量
    1955
  • 访问量
    10367007