Mysql事務隔離級別和鎖機制


一.Spring支持四種事務隔離級別:

1.ISOLATION_READ_UNCOMMITTED(讀未提交):這是事務最低的隔離級別,它充許令外一個事務可以看到這個事務未提交的數據。

2.ISOLATION_READ_COMMITTED(讀已提交): 保證一個事務修改的數據提交后才能被另外一個事務讀取。另外一個事務不能讀取該事務未提交的數據

3.ISOLATION_REPEATABLE_READ(可重復讀): 這種事務隔離級別可以防止臟讀,不可重復讀。但是可能出現幻像讀。

4.ISOLATION_SERIALIZABLE(可串行化) 這是花費最高代價但是最可靠的事務隔離級別。事務被處理為順序執行。

spring設置中還有一個默認級別:

ISOLATION_DEFAULT:使用數據庫默認的事務隔離級別。

 

二、一些名詞

多個事務並發會產生一些問題:

臟讀:可以讀取到其他事務修改但未提交的臟數據。

不可重復讀:在一個事務中重復讀取相同數據。在其中兩次讀取數據之間有另一個事務修改並提交了該數據。使得事務兩次讀到的數據是不一樣的。

幻讀: 第一個事務對一個表中的數據進行了修改,這種修改涉及 到表中的全部數據行。同時,第二個事務也修改這個表中的數據,這種修改是向表中插入一行新數據。那么,以后就會發生操作第一個事務的用戶發現表中還有沒有 修改的數據行,就好象發生了幻覺一樣。

丟失更新: 多個用戶同時對一個數據資源進行更新,必定會產生被覆蓋的數據,造成數據讀寫異

 

例子:假定有數據表

==student==

id | name

1  | 張三

a.臟讀

事務A:select name from student where id=1;

事務B:update  student set name='李四' where id=1;不提交

結果:可能是“李四”

讀已提交:避免讀取未提交數據。

 

b.不可重復讀

事務A:select name from student where id=1;

      select name from student where id=1;

事務B:update  student set name='李四' where id=1;提交

結果:第一次讀到“張三”,第二次可能讀到“李四”

可重復讀:避免事務B修改id為1的數據。但是事務B可以向表中新增數據李四

 

c.幻讀

事務A:select name from student;

      select name from student;

事務B:insert into student values(default,'李四');提交

結果:第一次讀到“張三”,第二次可能讀到"張三"和"李四"

串行化讀:每次讀都需要獲得表級共享鎖,讀寫相互都會阻塞。可避免幻讀。

各種隔離級別與各種讀的關系:

 

三、MySQL默認隔離級別

 MySQL/InnoDB默認是可重復讀的(REPEATABLE READ)

Oracle默認隔離級別是讀已提交READ_COMMITTED);

 

四、修改與查詢MySQL事務隔離級別的方法:

 1 #查全局事務隔離級別
 2 SELECT @@global.tx_isolation;
 3 #查當前會話事務隔離級別
 4 SELECT @@session.tx_isolation; 
 5 #查當前事務隔離級別
 6 SELECT @@tx_isolation;
 7 #設置全局隔離級別
 8 set global transaction isolation level read committed;
 9 #設置當前會話隔離級別
10 set session transaction isolation level read committed;

其它隔離級別的設置就不說了。

測試,以root身份登陸,修改session.tx_isolation:

退出mysql,再次以root身份登陸,上次會話的設置失效:

更換身份,使用foreigner身份登陸,修改全局權限:

再次以root身份登陸,查看權限:

可見,全局事務隔離級別是MySQL全局的,與某個用戶的或者某個會話的隔離級別沒有關系。

 

 五、鎖機制

定義:當有事務操作時,數據庫引擎會要求不同類型的鎖定,如相關數據行、數據頁或是整個數據表,當鎖定運行時,會阻止其他事務對已經鎖定的數據行、數據頁或數據表進行操作。只有在當前事務對於自己鎖定的資源不在需要時,才會釋放其鎖定的資源,供其他事務使用。

我個人對鎖的理解是,某線程想要執行某個事務中的某條sql,必須得有某個鎖。如果沒有該鎖,要等待自己獲得該鎖后才能執行相應操作。

共享鎖(Share)

共享鎖的代號是S,共享鎖的鎖粒度是行或者元組(多個行)。一個事務獲取了共享鎖之后,可以對鎖定范圍內的數據執行讀操作。

排它鎖(eXclusive)

排它鎖的代號是X,是eXclusive的縮寫,排它鎖的粒度與共享鎖相同,也是行或者元組。一個事務獲取了排它鎖之后,可以對鎖定范圍內的數據執行寫操作。

意向鎖

意向鎖的含義是如果對一個結點加意向鎖,則說明該結點的下層結點正在被加鎖;對任一結點加鎖時,必須先對它的上層結點加意向鎖。如:對表中的任一行加鎖時,必須先對它所在的表加意向鎖,然后再對該行加鎖。這樣一來,事務對表加鎖時,就不再需要檢查表中每行記錄的鎖標志位了,系統效率得以大大提高。

簡單的說就是我要對哪個表進行事務操作了,就給哪個表加一個意向鎖。

鎖的互斥與兼容關系

鎖和鎖之間的關系,要么是相容的,要么是互斥的。

鎖a和鎖b相容是指:操作同樣一組數據時,如果事務t1獲取了鎖a,另一個事務t2還可以獲取鎖b;

鎖a和鎖b互斥是指:操作同樣一組數據時,如果事務t1獲取了鎖a,另一個事務t2在t1釋放鎖a之前無法獲取鎖b。

上面提到的共享鎖、排它鎖、意向共享鎖、意向排它鎖相互之前都是有兼容/互斥關系的,可以用一個兼容性矩陣表示(y表示相容,n表示互斥):

 

六、悲觀鎖和樂觀鎖

悲觀鎖(Pessimistic Lock), 每次去拿數據的時候都認為別人會修改,所以每次在拿數據的時候都會上鎖,這樣別人想拿這個數據就會block直到它拿到鎖。傳統的關系型數據庫里邊就用到了很多這種鎖機制,比如行鎖,表鎖等,讀鎖,寫鎖等,都是在做操作之前先上鎖。

樂觀鎖(Optimistic Lock), 每次去拿數據的時候都認為別人不會修改,所以不會上鎖,但是在更新的時候會判斷一下在此期間別人有沒有去更新這個數據,可以使用版本號等機制。樂觀鎖適用於多讀的應用類型,這樣可以提高吞吐量,像數據庫如果提供類似於write_condition機制的其實都是提供的樂觀鎖。

兩種鎖各有優缺點,不可認為一種好於另一種,像樂觀鎖適用於寫比較少的情況下,即沖突真的很少發生的時候,這樣可以省去了鎖的開銷,加大了系統的整個吞吐量。但如果經常產生沖突,上層應用會不斷的進行retry,這樣反倒是降低了性能,所以這種情況下用悲觀鎖就比較合適。

 

七、丟失更新及解決方法。

丟失更新:

假設沒有X鎖存在。執行A,B兩個事務。下面這種情況事務A的提交會被事務B的提交覆蓋

解決辦法,加入X鎖即可。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM