加鎖查詢 FOR UPDATE 解決表格查詢極慢的問題

Select...for update 語句是我們經常使用手工加鎖語句。通常情況下,select語句是不會對數據加鎖,妨礙影響其他的DML和DDL操作。同時,在多版本一致讀機制的支持下,select語句也不會被其他類型語句所妨礙。

藉助for update子句,我們可以在應用程序的層面手工實現數據加鎖保護操作。

加鎖範圍子句:

在select ....for update 之後,可以使用of子句選擇對select的特定數據表進行加鎖操作。默認情況下,不使用of子句表示在select所有的數據表中加鎖。

// 採用默認格式for update------select * from emp where  rownum<2 for udpate;

此時,我們觀察v$lock和v$locked_object視圖,可以看到鎖信息。

// 事務信息視圖-------select addr ,xidusn,xidslot,sdsqn from v$transaction;

//鎖對象信息

SQL> select xidusn,xidslot,xidsqn,object_id,session_id, oracle_username from v$locked_object;


從上面的情況看,默認情況下的for update語句,效果相當於啓動了一個會話級別的事務,在對應的數據表(select所涉及的所有數據表)上加入一個數據表級共享鎖(TMlmode=3)。同時,在對應的數據行中加入獨佔鎖(TXlmode=6)。


根據我們以前的知識,如果此時有另一個會話視圖獲取對應數據行的獨佔權限(無論是用update/delete還是另一個for update),都會以block而告終。


for update子句的默認行爲就是自動啓動一個事務,藉助事務的鎖機制將數據進行鎖定。


Of子句是配合for update語句使用的一個範圍說明標記。從官方的語法結構看,後面可以跟一個或者多個數據列列表。這種語法場景常常使用在進行連接查詢的select中,對其中一張數據表數據進行鎖定。


SQL> select empno,ename,job,mgr,sal from emp,dept where emp.deptno=dept.deptno and empno=7369 for update of emp.empno;



當我們進行for update的操作時,與普通select存在很大不同。一般select是不需要考慮數據是否被鎖定,最多根據多版本一致讀的特性讀取之前的版本。加入for update之後,Oracle就要求啓動一個新事務,嘗試對數據進行加鎖。如果當前已經被加鎖,默認的行爲必然是block等待。

 

使用nowait子句的作用就是避免進行等待,當發現請求加鎖資源被鎖定未釋放的時候,直接報錯返回。



//變換session,進行執行。

SQL> select * from emp for update nowait;


select * from emp for update nowait

 

ORA-00054:資源正忙,但指定以NOWAIT方式獲取資源,或者超時失效

 

 

對應的還有就是wait子句,也就是默認的for update行爲。一旦發現對應資源被鎖定,就等待blocking,直到資源被釋放或者用戶強制終止命令。



wait子句還存在一個數據參數位,表示當出現blocking等待的時候最多等待多長時間。單位是秒級別。

//接上面的案例

SQL> select * from emp for update wait 3;

 

select * from emp for update wait 3

 

ORA-30006:資源已被佔用;執行操作時出現WAIT超時



Skip locked參數是最新引入到for update語句中的一個參數。簡單的說,就是在對數據行進行加鎖操作時,如果發現數據行被鎖定,就跳過處理。這樣for update就只針對未加鎖的數據行進行處理加鎖。

 

//session1中,對一部分數據加鎖;

SQL> select * from emp where rownum<4 for update;



for update的使用

 

在日常中,我們對for update的使用還是比較普遍的,特別是在如pl/sql developer中手工修改數據。此時只是覺得方便,而對for update真正的含義缺乏理解。

 

For updateOracle提供的手工提高鎖級別和範圍的特例語句。Oracle的鎖機制是目前各類型數據庫鎖機制中比較優秀的。所以,Oracle認爲一般不需要用戶和應用直接進行鎖的控制和提升。甚至認爲死鎖這類鎖相關問題的出現場景,大都與手工提升鎖有關。所以,Oracle並不推薦使用for update作爲日常開發使用。而且,在平時開發和運維中,使用了for update卻忘記提交,會引起很多鎖表故障。

 

那麼,什麼時候需要使用for update?就是那些需要業務層面數據獨佔時,可以考慮使用for update。場景上,比如火車票訂票,在屏幕上顯示郵票,而真正進行出票時,需要重新確定一下這個數據沒有被其他客戶端修改。所以,在這個確認過程中,可以使用for update。這是統一的解決方案方案問題,需要前期有所準備


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章