1、悲觀鎖和樂觀鎖
咱們常常在開發中遇到數據庫併發處理時,處理不一致的問題。須要對程序作併發控制。
典型的併發時出現的衝突有兩種:
一、丟失更新:一個事務的更新覆蓋了其它事務的更新結果,就是所謂的更新丟失。
例如X=0 A1把X=X+1 A2也設置X=X+1 若是A1和A2同時執行,可能出現最終X=1的狀況。而咱們須要獲得的是X=2 。 這就須要update處理爲串行化的。
二、髒讀:讀到的數據多是舊的。 初使X=0 A1把X設置爲1,A2讀取時X是1,但A1後面又修改爲了2,或回滾到了0,那麼A2讀取的數據就是髒數據。
A2讀取的是未提交的數據。通常數據庫不會設爲讀未提交,因此通常不會出現髒讀。
那什麼是樂觀鎖,什麼是悲觀鎖。
悲觀鎖:須要使用數據庫的鎖機制,如數據庫有表級排它鎖,有行級排它鎖。
假定一切操做均可能發現併發衝突,因此採起悲觀態度。經過加鎖,屏蔽一切可能違反數據完整性的操做
比方select * from table for update; 就是表鎖,
select * from table where x = 1 for update; 就是行鎖。
當使用for update後,其它會話仍是能夠執行select操做,但沒法執行select xx for update操做,只有當前會話commit後,其它for update操做纔會被執行。
典型例子能夠參考quartz集羣的鎖機制:http://blog.itpub.net/11627468/viewspace-1764753/
固然,此時也不能夠update,update須要等select xx for update 所在會話commit後才能執行。
注:mysql須要設置autocommit=0
樂觀鎖:其實不是真實的去鎖住記錄不讓訪問,或者不讓更新。
假定操做不多發生衝突,通常對於讀多寫少的狀況。只在提交操做時檢查是否違反數據完整性。[1] 樂觀鎖不能解決髒讀的問題。
能夠經過版本號是否比上個版本號或者時間戳來實現。
對於衝突檢測後的處理,須要業務邏輯去處理。
2、排它鎖和共享鎖
在數據庫中有兩種基本的鎖類型:排它鎖(Exclusive Locks,即X鎖)和共享鎖(Share Locks,即S鎖)。
當數據對象被加上排它鎖時,其餘的事務不能對它讀取和修改。加了共享鎖的數據對象能夠被其餘事務讀取,但不能修改。
數據庫利用這兩種基本的鎖類型來對數據庫的事務進行併發控制。
3、表級鎖和行級鎖
DML鎖的目的在於保證併發狀況下的數據完整性,主要包括TM鎖和TX鎖,其中TM鎖稱爲表級鎖,TX鎖稱爲事務鎖或行級鎖。
當Oracle執行DML語句時,系統自動在所要操做的表上申請TM類型的鎖。當TM鎖得到後,系統再自動申請TX類型的鎖,並將實際鎖定的數據行的鎖標誌位進行置位。這樣在事務加鎖前檢查TX鎖相容性時就不用再逐行檢查鎖標誌,而只需檢查TM鎖模式的相容性便可,大大提升了系統的效率。TM鎖包括了SS、SX、S、X等多種模式,在數據庫中用0-6來表示。不一樣的SQL操做產生不一樣類型的TM鎖。
值 鎖模式 鎖描述 SQL
0 NONE 1 NULL 空 SELECT
2 SS(ROW-S) 行級共享鎖
其餘對象只能查詢這些數據行 SELECT FOR UPDATE、LOCK FOR UPDATE、
LOCK ROW SHARE
3 SX(ROW-X) 行級排它鎖
在提交前不容許作DML操做 INSERT、UPDATE、DELETE、
LOCK ROW SHARE
4 S(SHARE) 共享鎖 CREATE INDEX、LOCK SHARE
5 SSX(S/ROW-X) 共享行級排它鎖 LOCK SHARE ROW EXCLUSIVE
6 X(eXclusive) 排它鎖 ALTER TABLE、DROP TABLE、DROP INDEX、
TRUNCATE TABLE、LOCK EXCLUSIVE
4、幾個問題
1.UPDATE/DELETE操做會將RS鎖定,直至操做被COMMIT或者ROLLBACK;
若操做未COMMIT以前其餘session對一樣的RS作變動操做,則操做會被hold,直至前session的UPDATE/DELETE操做被COMMIT;
2.session內外SELECT的RS範圍
前提:INSERT、UPDATE操做未COMMIT以前進行SELECT;
若在同一session內,SELECT出來的RS會包括以前INSERT、UPDATE影響的記錄;
若不在同一session內,SELECT出來的RS不會包括未被COMMIT的記錄;
3.SELECT.... FOR UPDATE [OF cols] [NOWAIT/WAIT] [SKIP LOCKED]
OF cols:只鎖定指定字段所在表的RS,而沒有指定的表則不會鎖定,只會在多表聯合查詢時出現;
NOWAIT:語句不會hold,而是直接返回錯誤ORA-00054: resource busy and acquire with NOWAIT specified;
WAIT N:語句被hold N秒,以後返回錯誤ORA-30006: resource busy; acquire with WAIT timeout expired;
SKIP LOCKED:不提示錯誤,而是直接返回no rows selected;
以上幾個選項能夠聯合使用的,比較推薦的有:
SELECT.... FOR UPDATE NOWAIT:對同一RS執行該SQL時,直接返回錯誤;
SELECT.... FOR UPDATE NOWAIT SKIP LOCKED:對同一RS執行該SQL時,直接返回空行;
PS:當RS被LOCK住以後,只對一樣請求LOCK的語句有效,對無需LOCK的SELECT語句並無任何影響;
以上悲觀鎖和樂內容參考:
http://www.cnblogs.com/guyufei/archive/2011/01/10/1931632.html
spring鎖實現參數:
http://blog.itpub.net/12158104/viewspace-374745
關於隔離級別能夠參考:
http://blog.itpub.net/11627468/viewspace-1793036/
關於數據庫的鎖能夠參考:
http://zhidao.baidu.com/link?url=zRnaslJ8INtEviT--BzrT2bMOqf4LJQzL-NQg2ECu6l-s-xPHi11bBlNjN2_zyNrwd9M0ZnbelQntmfYPB0ifqhtml