InnoDB 實現了兩種類型的鎖機制:共享鎖(S)和排他鎖(X)。共享鎖容許一個事務讀數據,不容許修改數據,若是其餘事務要再對該行加鎖,只能加共享鎖;排他鎖是修改數據時加的鎖,能夠讀取和修改數據,一旦一個事務對該行數據加鎖,其餘事務將不能再對該數據加任務鎖。數據庫
共享鎖(S) | 排它鎖(X) | |
---|---|---|
共享鎖(S) | 容許 | 不容許 |
排它鎖(X) | 不容許 | 不容許 |
x軸:事務A擁有的鎖
y軸:事務B申請的鎖微信
注
:一個事務在某一行數據上加上排它鎖後,其餘事務不能再在這行數據加任何鎖,沒法進行 update 與 delete,可是普通的 select 是能夠的,由於普通的 select 不加任何鎖,當 select .... from ... for update 時纔會加上排它鎖。併發
1.數據丟失(兩個事務同時修改一行數據,其中一個事務異常回滾,致使更新失敗)spa
解決辦法:未提交讀(Read Uncommitted):在事務 B 讀取數據時,事務 A 讀取數據加了共享鎖,修改數據時加了排它鎖。這種隔離級別,會致使髒讀、不可重複讀以及幻讀。3d
未提交讀會致使髒讀、不可重複讀、幻讀的緣由:儘管 A 持有排它鎖,避免了兩個事務同時修改的狀況,可是普通的 select 不持有鎖,仍是能夠讀到數據的,因此事務 A 屢次修改數據,事務 B 中的查詢仍是能夠看到的。code
2.髒讀(一個事務的執行期間,另外一個事務讀到了沒有提交數據)blog
解決辦法:已提交讀(Read Committed):在事務 B 讀取數據時增長了共享鎖,一旦讀取,當即釋放鎖
,事務 A 讀取修改數據時增長了行級排他鎖,直到事務結束才釋放鎖。
也就是說,事務 B 在讀取數據時,事務 A 只能讀取數據,不能修改。當事務 B 讀取到數據後,事務 A 才能修改。
這種隔離級別,能夠避免髒讀,但依然存在不可重複讀以及幻讀的問題。事務
已提交讀會致使不可重複讀、幻讀的緣由:事務 B 沒有提交就將鎖釋放,致使事務 A 能夠對數據進行任意修改,修改後,事務 B 再次獲取共享鎖查詢,查詢到跟以前讀取不一致的數據。rem
3.不可重複讀(一個事務的執行期間,另外一個事務連續兩次讀取到的值不同)it
解決辦法:可重複讀(Repeatable Read):在事務 B 讀取數據時增長了共享鎖,事務結束,才釋放鎖
,事務 A 讀取修改數據時增長了行級排他鎖,直到事務結束才釋放鎖。
也就是說,事務 B 在沒有結束事務時,事務 A 只能讀取數據,不能修改。當事務 B 結束事務,事務 A 才能修改。
這種隔離級別,能夠避免髒讀、不可重複讀,但依然存在幻讀的問題。
可重複讀致使幻讀的緣由:可重複讀是加的行級鎖,而幻讀是知足查詢條件的前提下數據量發生變化,即發生 insert 或 delete操做。
4.幻讀(一個事務的執行期間,另外一個事務連續兩次讀取到的數量不一樣)
解決辦法:可序列化(Serializable):在事務 A 讀取數據時增長了共享鎖,事務結束,才釋放鎖,事務 B 讀取修改數據時增長了表級排他鎖
,直到事務結束才釋放鎖。
可序列化解決了髒讀、不可重複讀、幻讀等問題,但隔離級別愈來愈高的同時,併發性會愈來愈低。
能夠看出,控制數據庫併發帶來的問題依賴的是鎖粒度的擴大來解決的。
可是隔離級別越大,併發性就越差,若是業務場景容許的狀況下,適當減少隔離級別是處理併發的一種手段。