關於 select ... for update 和 for update nowait

zhangsharp20發表於2014-09-16
通常,select ... for update是為了鎖定相關的行,保證在查詢期間到釋放的時候,相關的行集在這個過程中不被其他會話進行寫操作(但是其他行集卻並無影響)。
比如,有表:
create table t ( id number);
insert into t select object_id from dba_objects where object_id<=100;
commit;
現在t表有100行資料,從1到100;
然後我們在兩個會話中進行測試: select ... for update
會話A     會話A執行結果 會話B 會話B執行結果
delete from t where id=2; 執行成功。
select * from t for update; 會話被掛起。
commit; 提交成功。 A會話提交後,B會話執行成功。得到結果集。
update t set id=-1 where  id =10;      會話被掛起。
執行成功。 commit或rollback(這裡實際上並無任何資料更改)。 提交成功或回滾成功。
這裡,我們看到。當某一行被會話A修改或刪除鎖定時,如果其他會話執行select for update,就會被掛起。直到會話A提交或回滾,釋放了鎖。
而當某個會話執行了select ... for update 後,其他會話身體在相關的行集進行寫操作(更新或刪除),也會被掛起,直到該會話解除鎖定。其他會話的寫操作才能完成。
 
那麼select ... for update nowait 又有什麼區別呢?
接下來測試 : select ... for update nowait
會話A     會話A執行結果 會話B 會話B執行結果
delete from t where id=2; 執行成功。
select * from t for update nowait;
立即返回錯誤。
 
第 1 行出現錯誤:
ORA-00054: 資源正忙, 但指定以 NOWAIT 方式獲取資源
commit; 提交成功。 A會話提交後,B會話執行成功。得到結果集。
update t set id=-1 where  id =10;      會話被掛起。
執行成功。 commit或rollback(這裡實際上並無任何資料更改)。 提交成功或回滾成功。
 
透過兩個比的對比發現。當使用 select ...  for update 的時候,如果有相關的行被鎖定。那麼,查詢會被掛起,直到其他會話的鎖定被解除。使用select ... for update nowait 的時候,如果有相關行被鎖定。不再是掛起,是直接返回一個資源忙的錯誤。
另外,無論是使用select ... fro update 還是使用 select ... fro update nowait。都會對相關的行集進行鎖定,其他會話進行相關行集的寫操作都會被掛起,直到該鎖定被解除。所以,在使用了select ... fro update或者 select ... fro update nowait 後,要儘快解除鎖定,避免其他會話掛起太久。

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

相關文章