Mysql事務隔離級別和鎖機制

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

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

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

3.ISOLATION_REPEATABLE_READ(可重複讀): 這種事務隔離級別能夠防止髒讀,不可重複讀。可是可能出現幻像讀。數據庫

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

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

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

 

2、一些名詞測試

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

髒讀:能夠讀取到其餘事務修改但未提交的髒數據。線程

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

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

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

 

例子:假定有數據表

==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,'李四');提交

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

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

各類隔離級別與各類讀的關係:

 

3、MySQL默認隔離級別

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

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

 

4、修改與查詢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全局的,與某個用戶的或者某個會話的隔離級別沒有關係。

 

 5、鎖機制

定義:當有事務操做時,數據庫引擎會要求不一樣類型的鎖定,如相關數據行、數據頁或是整個數據表,當鎖定運行時,會阻止其餘事務對已經鎖定的數據行、數據頁或數據表進行操做。只有在當前事務對於本身鎖定的資源不在須要時,纔會釋放其鎖定的資源,供其餘事務使用。

我我的對鎖的理解是,某線程想要執行某個事務中的某條sql,必須得有某個鎖。若是沒有該鎖,要等待本身得到該鎖後才能執行相應操做。

共享鎖(Share)

共享鎖的代號是S,共享鎖的鎖粒度是行或者元組(多個行)。一個事務獲取了共享鎖以後,能夠對鎖定範圍內的數據執行讀操做。

排它鎖(eXclusive)

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

意向鎖

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

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

鎖的互斥與兼容關係

鎖和鎖之間的關係,要麼是相容的,要麼是互斥的。

鎖a和鎖b相容是指:操做一樣一組數據時,若是事務t1獲取了鎖a,另外一個事務t2還能夠獲取鎖b;

鎖a和鎖b互斥是指:操做一樣一組數據時,若是事務t1獲取了鎖a,另外一個事務t2在t1釋放鎖a以前沒法獲取鎖b。

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

 

6、悲觀鎖和樂觀鎖

悲觀鎖(Pessimistic Lock), 每次去拿數據的時候都認爲別人會修改,因此每次在拿數據的時候都會上鎖,這樣別人想拿這個數據就會block直到它拿到鎖。傳統的關係型數據庫裏邊就用到了不少這種鎖機制,好比行鎖,表鎖等,讀鎖,寫鎖等,都是在作操做以前先上鎖。

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

兩種鎖各有優缺點,不可認爲一種好於另外一種,像樂觀鎖適用於寫比較少的狀況下,即衝突真的不多發生的時候,這樣能夠省去了鎖的開銷,加大了系統的整個吞吐量。但若是常常產生衝突,上層應用會不斷的進行retry,這樣反卻是下降了性能,因此這種狀況下用悲觀鎖就比較合適。

 

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

丟失更新:

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

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

相關文章
相關標籤/搜索