【為什麼要鎖】
資料庫是乙個多使用者使用的共享資源,比如乙個使用者表t_user,兩個瀏覽器前面的人登入了同個乙個賬號,把**號碼改了。當多個使用者併發地訪問資料時,在資料庫中就會產生多個事務同時訪問同一資料的情況。若對併發操作不加控制就可能會讀取和儲存不正確的資料,破壞資料庫的一致性(髒讀,不可重複讀,幻讀等),可能產生死鎖。為了解決這個問題,加鎖是乙個非常重要的技術,對實現資料庫併發控制是乙個好的方案。簡單說,當乙個執行sql語句的事務想要操作表記錄之前,先向資料庫發出請求,對你訪問的記錄集加鎖,在這個事務釋放這個鎖之前,其他事務不能對這些資料進行更新操作。
【有哪些鎖】
鎖包括行級鎖、表級鎖、悲觀鎖、樂觀鎖
表級鎖:5種
行共享 (row share) – 禁止排他鎖定表,與行排他類似,區別是別的事務還可以在此表上加任何排他鎖。(除排他(exclusive)外)
行排他(row exclusive) – 禁止使用排他鎖和共享鎖,其他事務依然可以併發地對相同資料表執行查詢,插入,更新,刪除操作,或對錶內資料行加鎖的操作,但不能有其他的排他鎖(自身是可以的,沒發現有什麼用)
共享鎖(share) - 鎖定表,對記錄唯讀不寫,多個使用者可以同時在同乙個表上應用此鎖,在表沒有被任何dml操作時,多個事務都可加鎖,但只有在僅乙個事務加鎖的情況下只有此事務才能對錶更新;當表已經被更新或者指定要更新時(select for update),任何事務都不能加此鎖了。
共享行排他(share row exclusive) – 比共享鎖更多的限制,禁止使用共享鎖及更高的鎖,在表沒有被任何dml操作時,只有乙個事務可以加鎖,可以更新,書上說別的事務可以使用select for update鎖定選中的資料行,可是實驗後沒被驗證。
排他(exclusive) – 限制最強的表鎖,僅允許其他使用者查詢該錶的行。禁止修改和鎖定表
行級鎖和表級鎖是根據鎖的粒度來區分的,行記錄,表都是資源,鎖是作用在這些資源上的。如果粒度比較小(比如行級鎖),可以增加系統的併發量但需要較大的系統開銷,會影響到效能,出現死鎖,,因為粒度小則操作的鎖的數量會增加;如果作用在表上,粒度大,開銷小,維護的鎖少,不會出現死鎖,但是併發是相當昂貴的,因為鎖定了整個表就限制了其它事務對這個表中其他記錄的訪問。
悲觀鎖:
pessimistic lock正如其名,它指的是對資料被外界(包括本系統當前的其他事務,以及來自外部系統的事務處理)修改持保守悲觀態度,事務每次去運算元據的時候都假設有其他事務會修改需要訪問的資料,所以在訪問之前都要求上鎖,行鎖,表鎖等,讀鎖,寫鎖等,都是在做操作之前先上鎖,因此,在整個資料處理過程中,將資料處於鎖定狀態。悲觀鎖的實現,往往依靠資料庫提供的鎖機制(也只有資料庫層提供的鎖機制才能 真正保證資料訪問的排他性,否則,即使在本系統中實現了加鎖機制,也無法保證外部系 統不會修改資料)。 乙個典型的倚賴資料庫的悲觀鎖呼叫: select * from account where name=」erica」 for update 這條sql 語句鎖定了account 表中所有符合檢索條件(name=」erica」)的記錄。 本次事務提交之前(事務提交時會釋放事務過程中的鎖),外界無法修改這些記錄。
hibernate悲歡鎖實現:基於資料庫鎖機制
query q=session.createquery("select * from t_profit where amount>10000");
q.setlockmode("profit",lockmode.upgrade);//profit是profit類的別名
listps=q.list();
執行的sql:select ....from t_profit where amount>10000 for update.hibernate的悲觀鎖通過資料庫的for update實現。
lockmode.none:無鎖機制;
lockmode.write:insert,update記錄時自動獲取悲觀鎖;
lockmode.read在讀取時自動獲取悲觀鎖;
lockmode.upgrade:利用資料庫的for update子句加鎖;
lockmode.upgrade_nowait:oracle特定實現,用oracle的for update nowait子句加鎖
樂觀鎖:
optimistic lock,和悲歡鎖相反,事務每次去運算元據之前,都假設其他事務不會修改這些需要訪問的資料 ,所以 在訪問之前不要求上鎖,只是在進行更新修改操作的時候判斷一下在訪問的期間有沒有其他人修改資料 了。它適用於多讀的應用型別,衝突真的發生比較少的時候就比較好,這樣省去了開銷的開銷,可以提高吞吐量;但如果是真的經常要發生衝突的,那每次還要去判斷進行retry,反倒降低的效能,這個時候悲歡鎖比較好。資料庫如果提供類似於write_condition機制的其實都是提供的樂觀鎖。
它的實現大多是基於資料版本versin記錄機制。舉個例子:
1.利潤表t_profit中有乙個 version欄位,當前值為1;而總資產餘額字段(balance)為$10000
2.操作員a讀出version=1,從總資產減除2000,10000-2000=8000.
3.a還沒操作結束,此時操作員b也讀出version=1,總資產減除5000,10000-5000=5000.
4.a操作完成,把version加1,修改為2,把總資產減2000後提交更新資料庫,更新成功
5.b操作了,也加version加1,修改為2,把總資產減5000後提交更新資料庫,此時發現version已經為2了,如b修改後加1的version一樣,不滿足樂觀鎖策略:"提交的版本必有大於記錄當前的版本才能執行"。因此b的操作請求被駁回,這樣就避免了b就version=1的舊資料修改的結果覆蓋了a操作的結果的可能。如沒有樂觀鎖,那a減去2000後剩餘8000,但b操作的時候是用10000-5000剩餘5000的,如果b的提交成功,總資產餘額就是5000,但實際情況應該是8000-5000=3000的。出現總資產表記錄和實際支出不一致。
hibernate對樂觀鎖的實現:
資料庫鎖機制
這段時間由於開發專案,重新學習了資料庫的併發控制和鎖機制。資料庫就是通過鎖機制來解決併發問題的。主要就是兩種鎖,共享鎖和排他鎖 也叫獨佔鎖 在執行select語句的時候需要給操作物件 表或者一些記錄 加上共享鎖,但加鎖之前需要檢查是否有排他鎖,如果沒有,則可以加共享鎖 乙個物件上可以加n個共享鎖 否...
資料庫鎖機制
這段時間由於開發專案,重新學習了資料庫的併發控制和鎖機制。資料庫就是通過鎖機制來解決併發問題的。主要就是兩種鎖,共享鎖和排他鎖 也叫獨佔鎖 在執行select語句的時候需要給操作物件 表或者一些記錄 加上共享鎖,但加鎖之前需要檢查是否有排他鎖,如果沒有,則可以加共享鎖 乙個物件上可以加n個共享鎖 否...
資料庫鎖機制
資料庫就是通過鎖機制來解決併發問題的。主要就是兩種鎖,共享鎖和排他鎖 也叫獨佔鎖 在執行select語句的時候需要給操作物件 表或者一些記錄 加上共享鎖,但加鎖之前需要檢查是否有排他鎖,如果沒有,則可以加共享鎖 乙個物件上可以加n個共享鎖 否則不行。共享鎖通常在執行完select語句之後被釋放,當然...