這裏主要講的是Mysql InnoDB引擎相關事務和鎖。Mysql事務主要和上訴數據庫理論中相似,有所不一樣的是在事務隔離級別的Repeatable Read(可重複讀)、和鎖有着不一樣的實現。html
Mysql一樣有4種事務隔離級別,其中Repeatable Read(可重複讀)是Mysql默認隔離級別,其經過MVCC機制實現了不會出現幻讀現象。mysql
隔離級別 | 髒讀 | 不可重複讀 | 幻讀 |
---|---|---|---|
Read Uncommitted | 可能 | 可能 | 可能 |
Read Committed | 不能 | 可能 | 可能 |
Repeatable Read | 不能 | 不能 | 不能 |
Serializable | 不能 | 不能 | 不能 |
Mysql能夠經過下訴API操做事務隔離級別:sql
查看系統隔離級別: select @@global.tx_isolation; 查看當前會話隔離級別 select @@tx_isolation; 設置當前會話隔離級別 SET session TRANSACTION ISOLATION LEVEL serializable; 設置全局系統隔離級別 SET GLOBAL TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
Mysql InnoDB引擎有悲觀鎖、樂觀鎖(MVCC),其共同組成Mysql相關鎖機制,而且Mysql經過其使用Repeatable Read可以防止幻讀的出現。數據庫
Mysql主要有下面4種悲觀鎖:網絡
IS、S、IX、X鎖的兼容性爲:session
Mysql InnoDB引擎默認支持行鎖,來儘可能縮小鎖定元組的粒度,行鎖分爲三級,粒度從小到大依次是:mvc
前面所說,樂觀鎖機制經過在表中添加version
字段進行實現。在Mysql InnoDB引擎中,其會在每行數據中額外添加兩個隱藏值來實現MVCC,這兩個值一個記錄這行數據什麼時候被建立,另一個記錄這行數據什麼時候更新(或者被刪除)。在實際操做中,每開啓一個新事務,事務的版本號就會遞增。.net
任何操做都不加鎖code
操做 | 鎖對應級別 |
---|---|
select * | 無鎖 |
select * for update | 排它鎖 |
select * lock in share mode | 共享鎖 |
insert | 排它鎖,行鎖中的記錄鎖 |
delete | 排它鎖,行鎖中的記錄鎖 |
update | 排它鎖,行鎖中的記錄鎖 |
操做 | 鎖對應級別 |
---|---|
select * | 樂觀鎖(MVCC機制),也叫快照讀(snapshot read) |
select * for update | 排它鎖 |
select * lock in share mode | 共享鎖 |
insert | 排它鎖,行鎖中的記錄鎖 |
delete | 排它鎖,行鎖中的防插入鎖 |
update | 排它鎖,行鎖中的防插入鎖 |
該隔離級別下,讀(select)下會加共享鎖,至關於select lock in share mode,寫會加排他鎖,讀寫互斥,至關於所有使用悲觀鎖實現事務隔離級別。htm
Mysql在Repeatable Read事務隔離級別下,經過MVCC機制、update和delete操做的防插入鎖解決可重複讀和幻讀問題。
這裏主要由Mysql的MVCC機制所解決的。mysql會在每行數據中額外添加什麼時候被建立
、什麼時候被更新
兩個版本號字段,在RP級別下,每一個操做對應得MVCC版本號字段的操做:
因此咱們由上可知在事務A在select操做時,事務B的update和delete操做並不會影響事務A的select操做。
幻讀問題咱們主要是因爲insert操做致使,因此這裏面主要涉及到select時有insert操做和update(delete)時有insert操做,下面主要講這兩種Mysql InnoDB引擎是如何解決的。
由上所訴解決可重複讀問題,該操做已由Mysql的MVCC機制所解決
該操做主要由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, +∞)的間隔鎖,其統稱爲防插入鎖。
https://tech.meituan.com/innodb-lock.html http://chenzhou123520.iteye.com/blog/1860954 https://blog.csdn.net/sadfishsc/article/details/51027734