for update 與where current of的問題
在剛學oracle時一直不明白for update 的作用,今天考試又遇到鬱悶半天,所以加以整理。
一:
1>首先for update是對錶的行進行鎖定。鎖定就好比我們學java Thread那一章時,為某個執行緒的run()枷鎖,當例項化出來多個執行緒時,它必須一個執行緒全部執行完後,釋放鎖其他執行緒才有機會執行。本文for update功能上一樣,就是為一個select語句枷鎖,這樣在對這個表進行update ,delete時就會處於等待狀態,等待selec執行commit或rollback(相當於執行緒釋放鎖)後,才可以對錶進行更改或刪除。
怎樣看效果呢?1:首先在“執行”-->cmd-->連線資料庫 執行select * from emp for update
2 :然後在開啟另一個視窗(就相當於建立了兩個使用者):“執行”-->cmd-->連線資料庫 執行update emp set sal=100;你會發現它不執行了。
2>那馬for update與for update of 有神馬區別呢?
1.select * from Table1 for update 鎖定表的所有行,只能讀不能寫
2 select * from Table1 where id = 1 for update 只鎖定id=1的行
3 select * from Table1 a join Table2 b on a.id=b.id for update 鎖定兩個表的所有記錄
4 select * from Table1 a join Table2 b on a.id=b.id where a.id = 10 for update 鎖定兩個表的中滿足條件的行
5. select * from Table1 a join Table2 b on a.id=b.id where a.id = 10 for update of a.id 只鎖定Table1中滿足條件的行
for update 是把所有的表都鎖點 for update of 根據of 後表的條件鎖定相對應的表
3>關於oracle:select...for update of columns
按照1>步驟執行1:select * from emp for update of sal在另一個視窗中執:2:update emp set job='clerk' where empno=10;按照2>的的思維我們可能認:“1”只鎖定了emp表的sal列,其實不然當執行“2”時,我們發現它任然不執行,所以for update of columns 是鎖定的與sal相關的行。那麼for update 與for update of 有神嗎區別呢?區別在於多表連線時;
例如:
按照1>分別執行 select ename,dname from emp,dept where emp.deptno=dept.deptno for update;
另一視窗執行:update dept set dname='haha'where deptno=10;我們發現dept表不能更改
當我們在 select ename,dname from emp,dept where emp.deptno=dept.deptno for update of sal;時
update dept set dname='haha'where deptno=10;可以在執行了。
由此我們可以綜結出:for update of columns 用在多表連線鎖定時,可以指定要鎖定的是哪幾張表,而如果表中的列沒有在for update of 後面出現的話,就意味著這張表其實並沒有被鎖定,其他使用者是可以對這些表的資料進行update操作的。這種情況經常會出現在使用者對帶有連線查詢的檢視進行操作場景下。使用者只鎖定相關表的資料,其他使用者仍然可以對檢視中其他原始表的資料來進行操作。
4>關於nowait與wait
SELECT ... FOR UPDATE [OF column_list][WAIT n|NOWAIT][SKIP LOCKED];
1:其中:
OF 子句用於指定即將更新的列,即鎖定行上的特定列。
NOWAIT不進行等待,如果這條語句的鎖沒被釋放,則會直接報出:系統資源正忙
WAIT 子句指定等待其他使用者釋放鎖的秒數,防止無限期的等待。
“使用FOR UPDATE WAIT”子句的優點如下:
1防止無限期地等待被鎖定的行;
2允許應用程式中對鎖的等待時間進行更多的控制。
3對於互動式應用程式非常有用,因為這些使用者不能等待不確定
4 若使用了skip locked,則可以越過鎖定的行,不會報告由wait n 引發的‘資源忙’異常報告 :
2:現在執行如下操作:
在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中指定了需修改的列,則只有與這些列相關的表的行才會被鎖定.
二:
1:
如果你想刪除或者更新被Select For Update引用的記錄,你可以使用Where Current Of語句
DECLARE
CURSOR CUR_NAME IS
SELECT * FROM EMP WHERE deptno=10 FOR UPDATE OF sal;
BEGIN
FOR REC IN CUR_NAME LOOP
UPDATE EMP SET sal =100 ;
END LOOP;
END;
上述pl/sql執行過之後我們發現emp表中所有的sal列資料都被更改,此時我們只想更改跟遊標對應的行,所以我們又到where current of執行遊標遍歷時的當前行就好像for(int i=0;i++;i<10){}where
current of與“i”的功能相似。所以當我們想執行遊標影響的行時,上我們可以把上面pl/sql快改為:
DECLARE
CURSOR CUR_NAME IS
SELECT JOB FROM EMP WHERE deptno=10 FOR UPDATE OF sal;
BEGIN
FOR REC IN CUR_NAME LOOP
UPDATE EMP SET sal =100 WHERE CURRENT OF CUR_NAME;
END LOOP;
END;
不知道你們明白不,反正我是明白了。哈哈