zoukankan      html  css  js  c++  java
  • oracle select for update

    OracleSelect For Update语句可以实现在读取数据后马上锁定相关资源,防止被其他session修改数据的目的。也就是我们常常谈到的“悲观锁定”(现实应用开发中,使用悲观锁定的情况少之又少,也许是因为乐观锁定的实现更加灵活和便捷的缘故)。
    这个小文儿做一个小小的实验,来看看Select For Update语句实现的行级锁定

    1.创建实验表table_sfu,并初始化三条数据
    sec@ora10g> create table table_sfu (a number);

    Table created.

    sec@ora10g> insert into table_sfu values (1);

    1 row created.

    sec@ora10g> insert into table_sfu values (2);

    1 row created.

    sec@ora10g> insert into table_sfu values (3);

    1 row created.

    sec@ora10g> commit;

    Commit complete.

    sec@ora10g> select * from table_sfu;

             A
    ----------
             1
             2
             3

    2.使用Select For Update语句得到第一条数据
    sec@ora10g> select * from table_sfu where a = 1 for update;

             A
    ----------
             1

    3.查看一下现在系统中的锁定情况,152会话(即上面语句所在的会话)获得了一个TX锁和一个TM锁了,锁定的表就是TABLE_SFU
    sec@ora10g> @lock

    lock        lock
    holder    holder         lock             lock request       blocked
    username  sessid SERIAL# type    id1  id2 mode    mode BLOCK  sessid
    -------- ------- ------- ---- ------ ---- ---- ------- ----- -------
    SEC          152   14985 TM    15396    0    3       0     0
    SEC          152   14985 TX   327722 1790    6       0     0
                 164       1 TS        3    1    3       0     0
                 165       1 CF        0    0    2       0     0
                 165       1 RS       25    1    2       0     0
                 165       1 XR        4    0    1       0     0
                 166       1 RT        1    0    6       0     0

    7 rows selected.

    sec@ora10g> col OWNER for a6
    sec@ora10g> col OBJECT_NAME for a10
    sec@ora10g> select OWNER,OBJECT_NAME,OBJECT_ID,OBJECT_TYPE from dba_objects where object_id = '15396';

    OWNER  OBJECT_NAM  OBJECT_ID OBJECT_TYPE
    ------ ---------- ---------- -------------------
    SEC    TABLE_SFU       15396 TABLE

    4.另外新打开一个session,执行以下修改任务
    sec@ora10g> update table_sfu set a = 100 where a = 1;
    OK,效果出现了,这里出现了“锁等待”现象,原因就是因为在第一个session中使用Select For Update语句锁定了第一行数据,不允许其他的session对它修改。

    5.这时系统中锁定情况如下,可以看到第一个session(session id是152)会话锁定了第二个session(session id是145)会话的事务
    sec@ora10g> @lock

    lock        lock
    holder    holder         lock             lock request       blocked
    username  sessid SERIAL# type    id1  id2 mode    mode BLOCK  sessid
    -------- ------- ------- ---- ------ ---- ---- ------- ----- -------
    SEC          145   11388 TM    15396    0    3       0     0
    SEC          152   14985 TM    15396    0    3       0     0
    SEC          152   14985 TX   327722 1790    6       0     1     145
                 164       1 TS        3    1    3       0     0
                 165       1 CF        0    0    2       0     0
                 165       1 RS       25    1    2       0     0
                 165       1 XR        4    0    1       0     0
                 166       1 RT        1    0    6       0     0

    8 rows selected.

    6.因为仅仅是锁定了第一条数据,所以其他记录可以顺利的进行修改,如下
    sec@ora10g> update table_sfu set a = 200 where a = 2;

    1 row updated.

    sec@ora10g> commit;

    Commit complete.

    7.解锁方式:commit或rollback后即完成锁定的接触

    8.反过来思考一下,如果Select For Update与要锁定的行已经在其他session中完成了修改,再执行回出现什么效果呢?这个很显然,同样的会出现“锁等待”的现象,不过我想强调的是,这里可以使用nowait和wait选项来进行“探测”待锁定行是否可被锁定
    实验效果如下:
    第一个session:
    sec@ora10g> update table_sfu set a = 100 where a = 1;

    1 row updated.

    第二个session:
    sec@ora10g> select * from table_sfu where a = 1 for update;
    此处是“锁等待”效果

    sec@ora10g> select * from table_sfu where a = 1 for update nowait;
    select * from table_sfu where a = 1 for update nowait
                  *
    ERROR at line 1:
    ORA-00054: resource busy and acquire with NOWAIT specified
    这里提示了错误,原因就是已经“探测”到该行已经被别的事务锁定,这里无法对其进行锁定操作。

    sec@ora10g> select * from table_sfu where a = 1 for update wait 3;
    select * from table_sfu where a = 1 for update wait 3
                  *
    ERROR at line 1:
    ORA-30006: resource busy; acquire with WAIT timeout expired
    这里提示的错误内容与上面的一样,不过这里wait 3表示,我等你三秒的时间,如果三秒过后还无法锁定资源,就报错。

    9.更进一步,请参考Oracle官方文档中相关的描述
    《for_update_clause ::=》
    http://download.oracle.com/docs/cd/B19306_01/server.102/b14200/statements_10002.htm#i2126016
    语法格式:
    FOR UPDATE
    [ OF [ [ schema. ]
           { table | view } . ]column
           [, [ [ schema. ]
                { table | view } . ]column
           ]...
    ]
    [ NOWAIT | WAIT integer ]

    同上述连接,搜索关键字“for_update_clause”可以得到每个选项的解释信息

    《Using the FOR UPDATE Clause: Examples 》
    http://download.oracle.com/docs/cd/B19306_01/server.102/b14200/statements_10002.htm#i2130052

    10.小结
    上面的小实验展示了一下Select For Update行级锁定的效果,Oracle的锁定机制还是非常的灵活的,基于这个锁定可以实现“悲观锁定”。

    -- The End --
  • 相关阅读:
    c++ vector容器的使用,序列倒叙reverse(),容器底部插入一个数值push_back()
    vs2015+opencv-3.2.0-vc14配置
    串的匹配算法--C语言实现
    顺序队列与链式队列--C语言实现
    链式栈-C语言实现
    顺序栈与两栈共享空间-C语言实现
    静态链表-C语言实现
    循环双向链表-C语言实现
    链表-C语言实现
    顺序表-C语言实现
  • 原文地址:https://www.cnblogs.com/pan11jing/p/1689711.html
Copyright © 2011-2022 走看看