(轉)資料庫oracle for update of和for update區別

chaobaojun發表於2013-03-20
http://www.2cto.com/database/201108/100797.html 

對比區別:
  select * from TTable1 for update 鎖定表的所有行,只能讀不能寫
  2  select * from TTable1 where pkid = 1 for update 只鎖定pkid=1的行
  3  select * from Table1 a join Table2 b on a.pkid=b.pkid for update 鎖定兩個表的所有記錄
  4 select * from Table1 a join Table2 b on a.pkid=b.pkid where a.pkid = 10 for update 鎖定兩個表的中滿足條件的行
  5. select * from Table1 a join Table2 b on a.pkid=b.pkid where a.pkid = 10 for update of a.pkid 只鎖定Table1中滿足條件的行
  for update 是把所有的表都鎖點 for update of 根據of 後表的條件鎖定相對應的表
  -----------
  關於NOWAIT(如果一定要用FOR UPDATE,我更建議加上NOWAIT)
  當有LOCK衝突時會提示錯誤並結束STATEMENT而不是在那裡等待(比如:要查的行已經被其它事務鎖了,當前的鎖事務與之衝突,加上nowait,當前的事務會結束會提示錯誤並立即結束 STATEMENT而不再等待).
  如果加了for update後 該語句用來鎖定特定的行(如果有where子句,就是滿足where條件的那些行)。當這些行被鎖定後,其他會話可以選擇這些行,但不能更改或刪除這些行,直到該語句的事務被commit語句或rollback語句結束為止。
  因為FOR   UPDATE子句獲得了鎖,所以COMMIT將釋放這些鎖。當鎖釋放了,該遊標就無效了。
  就是這些區別了
 
關於oracle中的select...for update of columns
問題,如下:select * from emp where empno = 7369 for update; 會對錶中員工編號為7369的記錄進行上鎖。其他使用者無法對該記錄進行操作,只能查詢。select * from emp where empno = 7369 for update of sal; 這條語句是不是意味著只對表中的7369 這一行的sal欄位的資料進行了上鎖,其他資料則可以被其他使用者做更新操作呢。學員測試結果為二條語句的效果是一樣的。其他使用者對整行都無法更新,那麼是不是意味著 for update of columns這句沒有什麼意義呢?

  這個問題估計很多玩ORACLE的同學們都沒有去思考過【網上相關的帖子不多】。現在將其功能講解一下。

  從單獨一張表的操作來看,上面二條語句的效果確實是相同的。但是如果涉及到多表操作的時候 for update of columns就起到了非常大的作用了。現假定有二個使用者,scott和mm。

scott執行語句:select * from emp e,dept d where e.deptno = d.deptno for update; --對二張表都進行了整表鎖定
mm執行語句:select * from scott.dept for update wait 3; --試圖鎖定scott使用者的dept表

結果是:
ERROR 位於第 1 行:
ORA-30006: 資源已被佔用; 執行操作時出現 WAIT 超時

現在,scott使用者先進行解鎖rollback,再在for update語句後面加上of columns,進行測試

scott執行語句:select * from emp e,dept d where e.deptno = d.deptno for update of sal ;
mm執行語句:select * from scott.dept for update wait 3;

結果是:
成功鎖定了dept表的資料.

mm再次執行語句:select * from scott.emp for update wait 3;

結果是:
ERROR 位於第 1 行:
ORA-30006: 資源已被佔用; 執行操作時出現 WAIT 超時

通過這段程式碼案例,我們可以得到結論,for update of columns 用在多表連線鎖定時,可以指定要鎖定的是哪幾張表,而如果表中的列沒有在for update of 後面出現的話,就意味著這張表其實並沒有被鎖定,其他使用者是可以對這些表的資料進行update操作的。這種情況經常會出現在使用者對帶有連線查詢的檢視進行操作場景下。使用者只鎖定相關表的資料,其他使用者仍然可以對檢視中其他原始表的資料來進行操作。
 
Oracle 的for update行鎖
 SELECT...FOR UPDATE 語句的語法如下:
  SELECT ... FOR UPDATE [OF column_list][WAIT n|NOWAIT][SKIP LOCKED];
其中:
  OF 子句用於指定即將更新的列,即鎖定行上的特定列。
  WAIT 子句指定等待其他使用者釋放鎖的秒數,防止無限期的等待。
  “使用FOR UPDATE WAIT”子句的優點如下:
  1防止無限期地等待被鎖定的行;
  2允許應用程式中對鎖的等待時間進行更多的控制。
  3對於互動式應用程式非常有用,因為這些使用者不能等待不確定
  4 若使用了skip locked,則可以越過鎖定的行,不會報告由wait n 引發的‘資源忙’異常報告

示例:
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');
現在執行如下操作:
在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 也就如此了吧,insert、update、delete操作預設加行級鎖,其原理和操作與select for update並無兩樣。
select for update of,這個of子句在牽連到多個表時,具有較大作用,如不使用of指定鎖定的表的列,則所有表的相關行均被鎖定,若在of中指定了需修改的列,則只有與這些列相關的表的行才會被鎖定。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/21861353/viewspace-756577/,如需轉載,請註明出處,否則將追究法律責任。

相關文章