oracle for update nowait和for update区别

oracle for update nowait和for update区别

Select...for update 语句是我们经常使用手工加锁语句。通常情况下,select语句是不会对数据加锁,妨碍影响其他的DML和DDL操作。借助for update子句,我们可以在应用程序的层面手工实现数据加锁保护操作。

一、加锁范围子句:

在select ....for update 之后,可以使用of子句选择对select的特定数据表进行加锁操作。默认情况下,不使用of子句表示在select所有的数据表中加锁。

二、使用for update的实例

  •  
  • SQL 代码   复制
  • 
    1select * from TTable1 for update --锁定表的所有行,只能读不能写
    2select * from TTable1 where pkid = 1 for update --只锁定pkid=1的行
    3select * from Table1 a join Table2 b on a.pkid=b.pkid for update --锁定两个表的所有记录
    4select * from Table1 a join Table2 b on a.pkid=b.pkid where a.pkid = 10 for update --锁定两个表的中满足条件的行
    5select * from Table1 a join Table2 b on a.pkid=b.pkid where a.pkid = 10 for update of a.pkid --只锁定Table1中满足条件的行
      
    		
  • 三、关于NOWAIT

    当有LOCK冲突时会提示错误并结束STATEMENT而不是在那里等待(比如:要查的行已经被其它事务锁了,当前的锁事务与之冲突,加上nowait,当前的事务会结束会提示错误并立即结束 STATEMENT而不再等待).
     

    如果加了for update后 该语句用来锁定特定的行(如果有where子句,就是满足where条件的那些行)。当这些行被锁定后,其他会话可以选择这些行,但不能更改或删除这些行,直到该语句的事务被commit语句或rollback语句结束为止。
     

    因为FOR UPDATE子句获得了锁,所以COMMIT将释放这些锁。当锁释放了,该游标就无效了。 

    “使用FOR UPDATE WAIT”子句的优点如下
     

    1、防止无限期地等待被锁定的行;
    2、允许应用程序中对锁的等待时间进行更多的控制。
    3、对于交互式应用程序非常有用,因为这些用户不能等待不确定
    4 、若使用了skip locked,则可以越过锁定的行,不会报告由wait n 引发的‘资源忙’异常报告

    四、for update for update nowait 的区别:

    1、首先一点,如果只是select 的话,Oracle是不会加任何锁的,也就是Oracle select 读到的数据不会有任何限制,虽然这时候有可能另外一个进程正在修改表中的数据,并且修改的结果可能影响到你目前select语句的结果,但是因为没有锁,所以select结果为当前时刻表中记录的状态。

    2、如果加入了for update Oracle一旦发现(符合查询条件的)这批数据正在被修改,则不会发出该select语句查询,直到数据被修改结束(被commit),马上自动执行这个select语句。

    3、同样,如果该查询语句发出后,有人需要修改这批数据(中的一条或几条),它也必须等到查询结束后(commit)后,才能修改。

    4、for update nowait for update 都会对所查询到得结果集进行加锁,所不同的是,如果另外一个线程正在修改结果集中的数据,for update nowait 不会进行资源等待,只要发现结果集中有些数据被加锁,立刻返回 ORA-00054错误,内容是资源正忙, 但指定以 NOWAIT 方式获取资源”。

    5、for update for update nowait 加上的是一个行级锁,也就是只有符合where条件的数据被加锁。如果仅仅用update语句来更改数据时,可能会因为加不上锁而没有响应地、莫名其妙地等待,但如果在此之前,for update NOWAIT语句将要更改的数据试探性地加锁,就可以通过立即返回的错误提示而明白其中的道理,或许这就是For UpdateNOWAIT的意义之所在。

    6、以for update for update nowait方式进行查询加锁,在select的结果集中,只要有任何一个记录在加锁,则整个结果集都在等待系统资源(如果是nowait,则抛出相应的异常)

    五、for update for update nowait 实例

    1、数据

  •  
  • SQL 代码   复制
  • 
    create table t(a varchar2(20),b varchar2(20)); 
    insert into t values('1','1'); 
    insert into t values('2','2'); 
    insert into t values('3','3'); 
    insert into t values('4','4'); 
    
    		
  • SQL调用

  •  
  • SQL 代码   复制
  • 
    
    --在plsql develope中打开两个sql窗口,
    --在1窗口中运行sql 
    
    select * from t where a='1' for update; 
    
    --在2窗口中运行sql1 
    1. select * from t where a='1'; --这一点问题也没有,因为行级锁不会影响纯粹的select语句
    
    --再运行sql2 
    2. select * from t where a='1' for update; --则这一句sql在执行时,永远处于等待状态,除非窗口1中sql被提交或回滚。
    
    --如何才能让sql2不等待或等待指定的时间呢? 我们再运行sql3 
    3. select * from t where a='1' for update nowait; --则在执行此sql时,直接报资源忙的异常。
    
    --若执行
    select * from t where a='1' for update wait 6; 则在等待6秒后,报 资源忙的异常。
    
    --如果我们执行sql4 
    4. select * from t where a='1' for update nowait skip Locked; --则执行sql时,即不等待,也不报资源忙异常。
    
    --在窗口1中执行:
    select * from t where rownum<=3 nowait skip Locked; 
    
    --在窗口2中执行:
    select * from t where rownum<=6 nowait skip Locked; 
    select for update 
    
    		
  • 备注:

    select for update of,这个of子句在牵连到多个表时,具有较大作用,如不使用of指定锁定的表的列,则所有表的相关行均被锁定,若在of中指定了需修改的列,则只有与这些列相关的表的行才会被锁定。

    标签: