Mysql事務和鎖


Mysql事務

這里主要講的是Mysql InnoDB引擎相關事務和鎖。Mysql事務主要和上訴數據庫理論中類似,有所不同的是在事務隔離級別的Repeatable Read(可重復讀)、和鎖有着不同的實現。

事務隔離級別

Mysql同樣有4種事務隔離級別,其中Repeatable Read(可重復讀)是Mysql默認隔離級別,其通過MVCC機制實現了不會出現幻讀現象。

隔離級別 臟讀 不可重復讀 幻讀
Read Uncommitted 可能 可能 可能
Read Committed 不能 可能 可能
Repeatable Read 不能 不能 不能
Serializable 不能 不能 不能

Mysql可以通過下訴API操作事務隔離級別:

查看系統隔離級別:
select @@global.tx_isolation;
查看當前會話隔離級別
select @@tx_isolation;
設置當前會話隔離級別
SET session TRANSACTION ISOLATION LEVEL serializable;
設置全局系統隔離級別
SET GLOBAL TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;

Mysql鎖

Mysql InnoDB引擎有悲觀鎖、樂觀鎖(MVCC),其共同組成Mysql相關鎖機制,並且Mysql通過其使用Repeatable Read能夠防止幻讀的出現。

Mysql悲觀鎖

Mysql主要有下面4種悲觀鎖:

  • 共享鎖(S鎖、多鎖): 事務獲得元組的共享鎖后,其它事務也只能獲得該元組的共享鎖,而不能獲得排它鎖;獲得共享鎖的事務可以對元組進行讀操作。
  • 排它鎖(X鎖,寫鎖): 事務獲得元組的排它鎖后,其它事務既不能獲得該元組的共享鎖,也不能獲得排它鎖;獲得排它鎖的事務可以對元組進行寫操作。
  • 意向共享鎖(IS鎖): 事務打算給數據行加行共享鎖,事務在給一個數據行加共享鎖前必須先取得該表的IS鎖。
  • 意向排它鎖(IX鎖): 事務打算給數據行加行排他鎖,事務在給一個數據行加排他鎖前必須先取得該表的IX鎖。

IS、S、IX、X鎖的兼容性為:

圖片來自網絡

Mysql InnoDB引擎默認支持行鎖,來盡量縮小鎖定元組的粒度,行鎖分為三級,粒度從小到大依次是:

  • 記錄鎖(Record Lock):單行
  • 間隔鎖(Gap Lock):一個開區間內的多行
  • 防插入鎖(Next-Key Lock):一個前開后閉區間內的多行,實際上是記錄鎖和間隔鎖的結合

Mysql樂觀鎖(MVCC)

前面所說,樂觀鎖機制通過在表中添加version字段進行實現。在Mysql InnoDB引擎中,其會在每行數據中額外添加兩個隱藏值來實現MVCC,這兩個值一個記錄這行數據何時被創建,另外一個記錄這行數據何時更新(或者被刪除)。在實際操作中,每開啟一個新事務,事務的版本號就會遞增。

Mysql事務隔離級別和其對應鎖級別

Read Uncommited

任何操作都不加鎖

Read Commited

操作 鎖對應級別
select * 無鎖
select * for update 排它鎖
select * lock in share mode 共享鎖
insert 排它鎖,行鎖中的記錄鎖
delete 排它鎖,行鎖中的記錄鎖
update 排它鎖,行鎖中的記錄鎖

Repeated Read

操作 鎖對應級別
select * 樂觀鎖(MVCC機制),也叫快照讀(snapshot read)
select * for update 排它鎖
select * lock in share mode 共享鎖
insert 排它鎖,行鎖中的記錄鎖
delete 排它鎖,行鎖中的防插入鎖
update 排它鎖,行鎖中的防插入鎖

Serializable

該隔離級別下,讀(select)下會加共享鎖,相當於select lock in share mode,寫會加排他鎖,讀寫互斥,相當於全部使用悲觀鎖實現事務隔離級別。

Mysql解決Repeatable Read事務隔離級別的可重復讀和幻讀問題

Mysql在Repeatable Read事務隔離級別下,通過MVCC機制、update和delete操作的防插入鎖解決可重復讀和幻讀問題。

可重復讀問題

這里主要由Mysql的MVCC機制所解決的。mysql會在每行數據中額外添加何時被創建何時被更新兩個版本號字段,在RP級別下,每個操作對應得MVCC版本號字段的操作:

  • select: 讀取創建版本號<=當前版本號,更新版本號為空或<=當前版本號
  • insert: 保存當前事務版本號為行的創建版本號
  • update: 保存當前事務版本號為行創建版本號,同時保存當前事務版本號到行更新版本號
  • delete: 保存當前事務版本號為行的更新版本號

所以我們由上可知在事務A在select操作時,事務B的update和delete操作並不會影響事務A的select操作。

幻讀問題

幻讀問題我們主要是由於insert操作導致,所以這里面主要涉及到select時有insert操作和update(delete)時有insert操作,下面主要講這兩種Mysql InnoDB引擎是如何解決的。

select時的insert操作

由上所訴解決可重復讀問題,該操作已由Mysql的MVCC機制所解決

update和delete時的insert操作

該操作主要由Mysql InnoDB引擎的防插入鎖(Next-Key Lock)解決的。防插入鎖的區間是根據索引來確定的。對於沒有索引的列會直接鎖表。下面是一個例子:

--------------------------------------------------------------------------------------------------
事務A                                              |                       事務B
--------------------------------------------------------------------------------------------------
begin                                              |                       begin
--------------------------------------------------------------------------------------------------
update isolation set name = '-2' where name = '2'; |
--------------------------------------------------------------------------------------------------
                                                   |      insert into isolation(name) values('2');
                                                   |      // 這里會阻塞等待
--------------------------------------------------------------------------------------------------------
commit                                             |                       
--------------------------------------------------------------------------------------------------------

注意:上面事務A的update操作會造成name='2'的行鎖和name=(-∞, 2]和[2, +∞)的間隔鎖,其統稱為防插入鎖。

Reference

https://tech.meituan.com/innodb-lock.html
http://chenzhou123520.iteye.com/blog/1860954
https://blog.csdn.net/sadfishsc/article/details/51027734


免責聲明!

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



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