1. 程式人生 > >mysql innodb事務的隔離級別和鎖的關係

mysql innodb事務的隔離級別和鎖的關係

兩段鎖:
加鎖階段:
1–讀操作時使用s鎖,即共享鎖,其他事務可以繼續加共享鎖,但不能加排它鎖
2–寫操作時使用x鎖,即排它鎖,其他事務不能加任何鎖
3–若加鎖不成功,則事務進入等待狀態,等待加鎖成功
解鎖階段:
當事務釋放了一個封鎖後,進入解鎖階段,其他事務不能加鎖

事務 加鎖/解鎖處理
begin;
insert into test ….. 加insert對應的鎖
update test set… 加update對應的鎖
delete from test …. 加delete對應的鎖
commit; 事務提交時,同時釋放insert、update、delete對應的鎖
這種方式雖然無法避免死鎖,但是兩段鎖協議可以保證事務的併發排程是序列化(序列化很重要,尤其是在資料恢復和備份的時候)的。

MySQL中鎖的種類:
MySQL中鎖的種類很多,有常見的表鎖和行鎖,也有新加入的Metadata Lock等等,
1–表鎖是對一整張表加鎖,雖然可分為讀鎖和寫鎖,但畢竟是鎖住整張表,會導致併發能力下降,一般是做ddl處理時使用。
2–行鎖則是鎖住資料行,這種加鎖方法比較複雜,但是由於只鎖住有限的資料,對於其它資料不加限制,所以併發能力強,MySQL一般都是用行鎖來處理併發事務。這裡主要討論的也就是行鎖。

事務的四種隔離級別:
在資料庫操作中,為了有效保證併發讀取資料的正確性,提出的事務隔離級別。我們的資料庫鎖,也是為了構建這些隔離級別存在的。
隔離級別 髒讀(Dirty Read) 不可重複讀(NonRepeatable Read) 幻讀(Phantom Read)
未提交讀(Read uncommitted) 可能 可能 可能
已提交讀(Read committed) 不可能 可能 可能
可重複讀(Repeatable read) 不可能 不可能 可能
可序列化(Serializable ) 不可能 不可能 不可能
1–未提交讀(Read Uncommitted):允許髒讀,也就是可能讀取到其他會話中未提交事務修改的資料
2–提交讀(Read Committed):只能讀取到已經提交的資料。Oracle等多數資料庫預設都是該級別 (不重複讀)
3–可重複讀(Repeated Read):可重複讀。在同一個事務內的查詢都是事務開始時刻一致的,InnoDB預設級別。在SQL標準中,該隔離級別消除了不可重複讀,但是還存在幻象讀
4–序列讀(Serializable):完全序列化的讀,每次讀都需要獲得表級共享鎖,讀寫相互都會阻塞
5–Read Uncommitted這種級別,資料庫一般都不會用,而且任何操作都不會加鎖,這裡就不討論了。

不可重複讀和幻讀的區別
很多人容易搞混不可重複讀和幻讀,確實這兩者有些相似。
但不可重複讀重點在於update和delete,
而幻讀的重點在於insert。
如果使用鎖機制來實現這兩種隔離級別,
1–在可重複讀中,該sql第一次讀取到資料後,就將這些資料加鎖,其它事務無法修改這些資料,就可以實現可重複讀了。但這種方法卻無法鎖住insert的資料,所以當事務A先前讀取了資料,或者修改了全部資料,事務B還是可以insert資料提交,這時事務A就會發現莫名其妙多了一條之前沒有的資料,這就是幻讀,不能通過行鎖來避免。
2–需要Serializable隔離級別 ,讀用讀鎖,寫用寫鎖,讀鎖和寫鎖互斥,這麼做可以有效的避免幻讀、不可重複讀、髒讀等問題,但會極大的降低資料庫的併發能力。
3–所以說不可重複讀和幻讀最大的區別,就在於如何通過鎖機制來解決他們產生的問題。
4–上文說的,是使用悲觀鎖機制來處理這兩種問題,但是MySQL、ORACLE、PostgreSQL等成熟的資料庫,出於效能考慮,都是使用了以樂觀鎖為理論基礎的MVCC(多版本併發控制)來避免這兩種問題。

悲觀鎖和樂觀鎖
悲觀鎖
在悲觀鎖的情況下,為了保證事務的隔離性,就需要一致性鎖定讀。讀取資料時給加鎖,其它事務無法修改這些資料。修改刪除資料時也要加鎖,其它事務無法讀取這些資料。
樂觀鎖
1–相對悲觀鎖而言,樂觀鎖機制採取了更加寬鬆的加鎖機制。悲觀鎖大多數情況下依靠資料庫的鎖機制實現,以保證操作最大程度的獨佔性。但隨之而來的就是資料庫效能的大量開銷,特別是對長事務而言,這樣的開銷往往無法承受。
2–而樂觀鎖機制在一定程度上解決了這個問題。樂觀鎖,大多是基於資料版本( Version )記錄機制實現。何謂資料版本?即為資料增加一個版本標識,在基於資料庫表的版本解決方案中,一般是通過為資料庫表增加一個 “version” 欄位來實現。讀取出資料時,將此版本號一同讀出,之後更新時,對此版本號加一。此時,將提交資料的版本資料與資料庫表對應記錄的當前版本資訊進行比對,如果提交的資料版本號大於資料庫表當前版本號,則予以更新,否則認為是過期資料。

Serializable
這個級別很簡單,讀加共享鎖,寫加排他鎖,讀寫互斥。使用的悲觀鎖的理論,實現簡單,資料更加安全,但是併發能力非常差。如果你的業務併發的特別少或者沒有併發,同時又要求資料及時可靠的話,可以使用這種模式。
參考地址:http://www.jb51.net/article/75452.htm