数据库锁-行级锁
????? 從字面上看,行級鎖的作用范圍肯定比表級鎖的作用范圍要小;行級鎖和表級鎖是根據鎖的粒度來區分的,行記錄,表都是資源,鎖是作用在這些資源上的。如果粒度比較小(比如行級鎖),可以增加系統的并發量但需要較大的系統開銷,會影響到性能,出現死鎖,,因為粒度小則操作的鎖的數量會增加;如果作用在表上,粒度大,開銷小,維護的鎖少,不會出現死鎖,但是并發是相當昂貴的,因為鎖定了整個表就限制了其它事務對這個表中其他記錄的訪問。
行級鎖:(tx鎖,也叫事務鎖)
一、悲觀鎖:數據庫行級鎖,目的是讓數據被查出來的時候就加上鎖,然后再執行下面的程序邏輯,這樣后面為了操作相同數據而進來的請求,就會在一開始就被攔住(這種效果千萬不要以為可以做防重復提交)
在操作DML(insert,update,delete)語句時,oracle會自動加上行級鎖,在select * from table for update 【of column】【nowait|wait 3】時,oracle也會自動加鎖?
單表 for update:
1. 一般在for update 時加nowait,這樣就不用等待其他事務執行了,一判斷有事務,立馬拋出錯誤。
下面簡單說一下 for update的四種情況:
1.1??? select * from table where id = '1001' for update 鎖住了這條數據,那么另外一個人對該筆數據進行DML操作或者也執行同樣的for update操作時,會檢測到這筆數據上有行級鎖,那么就會等待著鎖釋放;這樣就會出現一個問題:其他的程序如果需要對這筆數據操作,就需要等,至于等多久要看鎖什么時候釋放!
1.2??? select * from table where id = '1001' for update nowait,意思就是如果這筆數據上本身加了鎖,另外一個人去執行這句SQL的時候,發現加了鎖,就會直接拋出異常(ORA-00054:資源正忙),不會等待這筆數據的鎖釋放。
1.3??? select * from table where id = '1001' for update wait 5;意思就是如果這筆數據被鎖住,另外一個人如果執行這句SQL后,會等待5秒,如果5秒后這句SQL還沒有得到這筆數據的鎖,就會拋出異常(ORA-00054:資源正忙)
1.4? 我們先執行 A語句:select * from table where id = '1001' for update 把1001加上鎖,然后再執行 B語句:select * from table where id = '1001' and id ='1002' for update;這時候肯定查不出來,因為A已經把B要加鎖的數據鎖了,這樣B聯1002的數據都查不出來
解決方案:skip locked如果把B語句改為:select * from table where id = '1001' and id ='1002' for update skip locked;意思就是執行的時候如果發現要查詢的數據有鎖,就把加了鎖的數據排除,把剩下的數據加鎖,然后查出來!
上面講到了 for update 的四種方式,實際情況如何選擇呢?
關于NOWAIT(如果一定要用FOR UPDATE,我更建議加上NOWAIT)??? 當有LOCK沖突時會提示錯誤并結束STATEMENT而不是在那里等待(比如:要查的行已經被其它事務鎖了,當前的鎖事務與之沖突,加上nowait,當前的事務會結束會提示錯誤并立即結束 STATEMENT而不再等待).??? WAIT 子句指定等待其他用戶釋放鎖的秒數,防止無限期的等待?! ?/p>
“使用FOR UPDATE WAIT”子句的優點如下:
1.防止無限期地等待被鎖定的行;
2.允許應用程序中對鎖的等待時間進行更多的控制?! ?/p>
3.對于交互式應用程序非常有用,因為這些用戶不能等待不確定
4.若使用了skip locked,則可以越過鎖定的行,不會報告由wait n 引發的‘資源忙’異常報告?
?
關聯表for update:
2. 現在大部分業務都是聯表查詢,如果用for update 的話,就會把所有關聯表查詢出來的列所在的行全部加鎖,那這個鎖可就重了,比如: select * from t1,t2 where t1.id = t2.id and t1.age = '20' for update;就會把T1和T2兩個表中符合條件的行鎖定;
如果上述SQL我只想對T1表的結果集加鎖,怎么辦?
答案:of column_name例子:
select * from t1,t2 where t1.id = t2.id and t1.age = '20' for update of t1.id;
這樣就會只把T1表中的符合條件的行加鎖,T2表中符合條件的行不會加鎖。
PS:如果單表for update of column_name查詢,其實和 for update操作是一樣的!
?
二、樂觀鎖:這不是數據庫本身的鎖,是利用數據比較結果來當做抽象的鎖;
舉個例子就明白:說明:小明成績錯了,要改成績。班主任能改,年級主任也能改!
程序:{
//先查出來小明的成績
select t.id,t.result from? T t where t.id='10001';---10001,59
//更新成績,改為60
update T t set t.result =‘60’ where t.id='10001'and t.result = '59'?
//加上這個條件的目的就是為了驗證,數據庫里10001的成績在此期間有沒有被其他人改過,如果改過,那就更新條數為0(因為找不到符合條件的數據);
PS:沒有找到數據,所以沒更新10001這筆數據,最好是程序返回一個沒有更新到這筆數據的提示,如果不加任何提示,前端就會認為更新成功了!
}
分析:
1.利用數據庫中的數據和已經取出的數據的一致性做為“鎖”,與for update相比,樂觀鎖機制是等到更改數據的時候才去校驗,悲觀鎖是讀取數據就開始做了校驗,
從這個角度來看,樂觀鎖是對數據庫沒有額外開銷,那么效率相對是高的。
2. 需要更改的字段可以作為樂觀鎖的驗證字段;或者表里建立version版本號,每更新一次數據版本號+1;或者加lastupdatedate(最后更新時間),同理:數據更改的同時lastupdatedate也跟著變更!
3.其實樂觀鎖存在一個很致命的問題:場景: 已上述小明改成績為例,假設班主任改的同時,年級主任也改,
兩個請求幾乎同時執行了查詢:select t.id,t.result from? T t where t.id='10001';---10001,59都查出來是59分!!
然后幾乎同時執行了改成績,班主任改成60分,年級主任改成了80分,關鍵是還都update到10001了
班主任:update T t set t.result =‘60’ where t.id='10001'and t.result = '59' ;
年級主任: update T t set t.result =‘80’ where t.id='10001'and t.result = '59' ;
這時候班主任事務先提交,數據庫小明成績改成了60,年級主任事務緊接著提交,小明的成績又從60改成了80,那么對于班主任來說,他的數據就是更新丟失!!!
所以大家使用起來要注意并發的情況!!
?
表級鎖:一般指的是表結構共享鎖。是不可對該表進行DDL操作,但是對于該表數據的DML操作不受影響表級鎖講的比較簡單,有興趣的朋友可以深入探究一下~
原文鏈接:https://blog.csdn.net/qq_32317661/article/details/80486102
總結
- 上一篇: 使用Nginx过滤网络爬虫
- 下一篇: linux相关(find/grep/aw