1. 隔離級(jí)別
1. read uncommitted
事務(wù)可以看見(jiàn)其他未提交事務(wù)的修改刘离。會(huì)導(dǎo)致臟讀捏题。
2. read committed
事務(wù)只能看見(jiàn)其他提交事務(wù)的修改。但是如果事務(wù)A讀取一批數(shù)據(jù)set,其他事務(wù)之后修改了這個(gè)數(shù)據(jù)set并提交(此時(shí)事務(wù)A沒(méi)有提交)刻肄,這時(shí)事務(wù)A再讀取數(shù)據(jù)set就跟第一次讀取的結(jié)果不一致。會(huì)導(dǎo)致不可重復(fù)讀融欧。
3. repeatable read
在事務(wù)執(zhí)行過(guò)程中敏弃,重復(fù)讀到的數(shù)據(jù)是一致的
4. serializable
2. 問(wèn)題
1. 臟讀
事務(wù)A讀到了事務(wù)B未提交的數(shù)據(jù)。(read uncommitted)
2. 不可重復(fù)讀
事務(wù)A第一次讀取行num噪馏,此時(shí)事務(wù)B修改行num并提交麦到,事務(wù)A再讀行num虹茶,數(shù)據(jù)會(huì)發(fā)生變化。(read uncommitted, read committed)
3. 幻讀
事務(wù)A第一次查詢范圍query_range隅要,返回n行蝴罪,此時(shí)事務(wù)B在該查詢范圍內(nèi)插入了一行數(shù)據(jù)并提交,事務(wù)A再次查詢范圍query_range會(huì)看到B插入的數(shù)據(jù)步清。(read uncommitted, read committed, repeatable read)
The so-called phantom problem occurs within a transaction when the same query produces different sets of rows at different times. For example, if a SELECT is executed twice, but returns a row the second time that was not returned the first time, the row is a “phantom” row.
在同一個(gè)事務(wù)執(zhí)行過(guò)程中要门,兩次相同的查詢,但是查詢的返回?cái)?shù)據(jù)行數(shù)不同廓啊。
隔離級(jí)別 | 臟讀 | 不可重復(fù)讀 | 幻讀 |
---|---|---|---|
read uncommitted | yes | yes | yes |
read committed | no | yes | yes |
repeatable read | no | no | yes |
serializable | no | no | no |
3. Innodb 行鎖算法
1. record lock 鎖住某一行
2. gap lock 鎖住兩行之間的間隙(不包括行本身)
3. next key lock 同時(shí)應(yīng)用1欢搜,2
4. 實(shí)例
0. current read, snapshot read
1. 實(shí)例1
- 隔離級(jí)別 repeatable read
- 數(shù)據(jù)庫(kù) mysql innodb
CREATE TABLE `test_lock` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`a` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `a` (`a`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
mysql> select * from test_lock;
+----+------+
| id | a |
+----+------+
| 1 | 1 |
| 2 | 2 |
| 3 | 3 |
| 4 | 4 |
| 5 | 5 |
| 6 | 6 |
+----+------+
6 rows in set (0.00 sec)
開啟sessionA, sessionB
sessionA> begin;
Query OK, 0 rows affected (0.01 sec)
sessionA> delete from test_lock where a=3;
Query OK, 1 row affected (0.00 sec)
sessionA>
此時(shí)鎖(行鎖、gap鎖)的情況如下圖,標(biāo)紅為加鎖谴轮,采用next key lock炒瘟。(不光在索引a上加鎖,索引a中3所對(duì)應(yīng)的主鍵索引也會(huì)加鎖第步,只畫了索引a)
注意:這里是主鍵索引的順序與a索引的順序一致的情況疮装。一致的情況下,新插入的4會(huì)插入在原來(lái)的4之后粘都。我們定義函數(shù)index_key(x), 表示獲取x所對(duì)應(yīng)的主鍵索引廓推,new(x)表示新插入的x,old(x)表示已經(jīng)存在的x翩隧。如果index_key(old(4))>index_key(new(4))樊展,那新的4是插不進(jìn)去的,因?yàn)樾碌?會(huì)被放在老的4的前面堆生。同理专缠,新插入的2也有可能插入進(jìn)去(只要index_key(new(2))<index_key(old(2)))。具體的例子整理后發(fā)出
對(duì)于sessionB淑仆,插入2涝婉,3失敗,插入4成功糯景。(如圖lock.png嘁圈,新插入的2會(huì)被2與3之間gap鎖阻止,新插入的3肯定失敗蟀淮,但是新插入的4就沒(méi)問(wèn)題)
sessionB> insert into test_lock(a) values(2);
^C^C -- query aborted
ERROR 1317 (70100): Query execution was interrupted
sessionB> insert into test_lock(a) values(3);
^C^C -- query aborted
ERROR 1317 (70100): Query execution was interrupted
sessionB> insert into test_lock(a) values(4);
Query OK, 1 row affected (0.00 sec)
2. 實(shí)例2
- 隔離級(jí)別 repeatable read
- 數(shù)據(jù)庫(kù) mysql innodb
驗(yàn)證實(shí)例1的另一種情況最住。
CREATE TABLE `test_lock` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`a` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `a` (`a`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
mysql> select * from test_lock2;
+----+------+
| id | a |
+----+------+
| 1 | 1 |
| 5 | 3 |
| 3 | 5 |
| 7 | 7 |
+----+------+
6 rows in set (0.00 sec)
開啟sessionA:
sessionA> begin;
sessionA> delete from test_lock2 where a=5;
這個(gè)時(shí)候情況如下圖所示:
如果按照實(shí)例1的分析,不看主鍵索引id怠惶,應(yīng)該插入(id=4,a=3)應(yīng)該會(huì)被gap鎖鎖定涨缚,但是事實(shí)是可以插入成功。因?yàn)椴迦氲?i4=d,a=3)放在了(id=5,a=3)的上面。
同樣的道理脓魏,不看主鍵索引id兰吟,通過(guò)實(shí)例1的分析,插入(id=6,a=7)應(yīng)該可以插入茂翔,但是事實(shí)不行混蔼,因?yàn)?id=6,a=7)被a=5與a=7之間的gap鎖阻止了。
新插入的(id=4, a=3)珊燎,需要判斷會(huì)插入在(id=5, a=3)之前還是之后惭嚣,很明顯之前(4<5),那么(id=3, a=5)與(id=5, a=3)之間的gap鎖不會(huì)阻止悔政。
新插入的(id=6, a=7)晚吞,需要判斷會(huì)插入在(id=7, a=7)之前還是之后,很明顯之前(6<7)谋国,那么(id=6, a=7)會(huì)被(id=3, a=5)與(id=5, a=3)與(id=7, a=7)之間的gap鎖阻止槽地。