【MySQL】可重复读模式下 unique key失效案例
生活随笔
收集整理的這篇文章主要介紹了
【MySQL】可重复读模式下 unique key失效案例
小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
一?【背景】
? ?今天上午文能提筆安天下,武能上馬定乾坤的登博給團(tuán)隊(duì)出了一道題目,誰(shuí)先復(fù)現(xiàn)問(wèn)題,獎(jiǎng)勵(lì)星巴克一杯。激起了一群忙碌的屌絲DBA的極大熱情。問(wèn)題是這樣滴,如下圖
登博提示了幾個(gè)細(xì)節(jié):
? ?1. code上的uk并未失效。
? ?2. rr隔離級(jí)別。
? ?3. 有并發(fā)線(xiàn)程的操作。
二 【原理分析】
1 事務(wù)隔離級(jí)別的基礎(chǔ)知識(shí):
2 MVCC 的讀操作
? ?在MVCC并發(fā)控制中,讀操作可以分成兩類(lèi):快照讀 (snapshot read)與當(dāng)前讀 (current read)。快照讀,讀取的是記錄的可見(jiàn)版本 (有可能是歷史版本),不用加鎖。
當(dāng)前讀,讀取的是記錄的最新版本,并且,當(dāng)前讀返回的記錄,都會(huì)加上鎖,保證其他事務(wù)不會(huì)再并發(fā)修改這條記錄。
快照讀:簡(jiǎn)單的select操作,屬于快照讀,不加鎖。
select * from table where ?;
當(dāng)前讀:特殊的讀操作,插入/更新/刪除操作,屬于當(dāng)前讀,需要加鎖。
select * from table where ? lock in share mode;
select * from table where ? for update;
insert into table values (…);
update table set ? where ?;
delete from table where ?;
所有以上的語(yǔ)句,都屬于當(dāng)前讀,讀取記錄的最新版本。并且,讀取之后,還需要保證其他并發(fā)事務(wù)不能修改當(dāng)前記錄,對(duì)讀取記錄加鎖。其中,除了第一條語(yǔ)句,對(duì)讀取記錄加S鎖 (共享鎖)外,其他的操作,都加的是X鎖 (排它鎖)。
注意:insert操作可能會(huì)觸發(fā)Unique Key的沖突檢查,也會(huì)進(jìn)行一個(gè)當(dāng)前讀。
?
三【解決.復(fù)現(xiàn)】
測(cè)試版本:?5.5.18 5.6.16 均可復(fù)現(xiàn)。
現(xiàn)在我們根據(jù)上述理論信息進(jìn)行復(fù)現(xiàn)問(wèn)題,具體的實(shí)現(xiàn)步驟如下:
注意 數(shù)據(jù)庫(kù)的隔離級(jí)別為RR?
當(dāng)session 2中將id=1 的刪除之后,session1 進(jìn)行insert操作時(shí),觸發(fā)unique key沖突檢查,此時(shí)因?yàn)閕d=1 code=20的數(shù)據(jù)已經(jīng)被物理刪除了,MySQL 檢查無(wú)沖突,進(jìn)行insert?insert into yy values(2,20,13); 便成功了。
四【結(jié)果展示】
五【參考資料】
?1 《MySQL 加鎖分析》
?2 《Innodb中的事務(wù)隔離級(jí)別和鎖的關(guān)系》 原文blog: http://blog.itpub.net/22664653/viewspace-1612574/
? ?今天上午文能提筆安天下,武能上馬定乾坤的登博給團(tuán)隊(duì)出了一道題目,誰(shuí)先復(fù)現(xiàn)問(wèn)題,獎(jiǎng)勵(lì)星巴克一杯。激起了一群忙碌的屌絲DBA的極大熱情。問(wèn)題是這樣滴,如下圖
登博提示了幾個(gè)細(xì)節(jié):
? ?1. code上的uk并未失效。
? ?2. rr隔離級(jí)別。
? ?3. 有并發(fā)線(xiàn)程的操作。
二 【原理分析】
1 事務(wù)隔離級(jí)別的基礎(chǔ)知識(shí):
- ?未提交讀(Read Uncommitted):允許臟讀,也就是可能讀取到其他會(huì)話(huà)中未提交事務(wù)修改的數(shù)據(jù)。
- ?提交讀(Read Committed):只能讀取到已經(jīng)提交的數(shù)據(jù)。Oracle等多數(shù)數(shù)據(jù)庫(kù)默認(rèn)都是該級(jí)別 (不重復(fù)讀)。
- ?可重復(fù)讀(Repeated Read):可重復(fù)讀。在同一個(gè)事務(wù)內(nèi)的查詢(xún)都是事務(wù)開(kāi)始時(shí)刻一致的,InnoDB默認(rèn)級(jí)別。在SQL標(biāo)準(zhǔn)中,該隔離級(jí)別消除了不可重復(fù)讀,但是還存在幻象讀。
- ?串行讀(Serializable):完全串行化的讀,每次讀都需要獲得表級(jí)共享鎖,讀寫(xiě)相互都會(huì)阻塞。
2 MVCC 的讀操作
? ?在MVCC并發(fā)控制中,讀操作可以分成兩類(lèi):快照讀 (snapshot read)與當(dāng)前讀 (current read)。快照讀,讀取的是記錄的可見(jiàn)版本 (有可能是歷史版本),不用加鎖。
當(dāng)前讀,讀取的是記錄的最新版本,并且,當(dāng)前讀返回的記錄,都會(huì)加上鎖,保證其他事務(wù)不會(huì)再并發(fā)修改這條記錄。
快照讀:簡(jiǎn)單的select操作,屬于快照讀,不加鎖。
select * from table where ?;
當(dāng)前讀:特殊的讀操作,插入/更新/刪除操作,屬于當(dāng)前讀,需要加鎖。
select * from table where ? lock in share mode;
select * from table where ? for update;
insert into table values (…);
update table set ? where ?;
delete from table where ?;
所有以上的語(yǔ)句,都屬于當(dāng)前讀,讀取記錄的最新版本。并且,讀取之后,還需要保證其他并發(fā)事務(wù)不能修改當(dāng)前記錄,對(duì)讀取記錄加鎖。其中,除了第一條語(yǔ)句,對(duì)讀取記錄加S鎖 (共享鎖)外,其他的操作,都加的是X鎖 (排它鎖)。
注意:insert操作可能會(huì)觸發(fā)Unique Key的沖突檢查,也會(huì)進(jìn)行一個(gè)當(dāng)前讀。
?
三【解決.復(fù)現(xiàn)】
測(cè)試版本:?5.5.18 5.6.16 均可復(fù)現(xiàn)。
現(xiàn)在我們根據(jù)上述理論信息進(jìn)行復(fù)現(xiàn)問(wèn)題,具體的實(shí)現(xiàn)步驟如下:
注意 數(shù)據(jù)庫(kù)的隔離級(jí)別為RR?
| session 1 | session 2 |
| root@test 08:47:41>set global tx_isolation='REPEATABLE-READ'; Query OK, 0 rows affected (0.00 sec) root@test 08:53:16>set autocommit=0; Query OK, 0 rows affected (0.00 sec) root@test 08:53:22>insert into yy values(1,20,13); Query OK, 1 row affected (0.00 sec) root@test 08:53:31>commit; Query OK, 0 rows affected (0.00 sec) root@test 08:53:39>select * from yy; +----+------+------+ | id | code | val? | +----+------+------+ |? 1 |?? 20 |?? 13 | +----+------+------+ 1 row in set (0.00 sec) | ? |
| ? | root@test 08:53:46>select * from yy; +----+------+------+ | id | code | val? | +----+------+------+ |? 1 |?? 20 |?? 13 | +----+------+------+ 1 row in set (0.00 sec) root@test 08:53:53>delete from yy where id=1; Query OK, 1 row affected (0.00 sec) root@test 08:53:59>commit; |
| root@test 08:54:10>insert into yy values(2,20,13); Query OK, 1 row affected (5.59 sec) root@test 08:54:23>select * from yy; +----+------+------+ | id | code | val? | +----+------+------+ |? 1 |?? 20 |?? 13 | |? 2 |?? 20 |?? 13 | +----+------+------+ 2 rows in set (0.00 sec) | ? |
當(dāng)session 2中將id=1 的刪除之后,session1 進(jìn)行insert操作時(shí),觸發(fā)unique key沖突檢查,此時(shí)因?yàn)閕d=1 code=20的數(shù)據(jù)已經(jīng)被物理刪除了,MySQL 檢查無(wú)沖突,進(jìn)行insert?insert into yy values(2,20,13); 便成功了。
四【結(jié)果展示】
五【參考資料】
?1 《MySQL 加鎖分析》
?2 《Innodb中的事務(wù)隔離級(jí)別和鎖的關(guān)系》 原文blog: http://blog.itpub.net/22664653/viewspace-1612574/
轉(zhuǎn)載于:https://www.cnblogs.com/cyt1153/p/6576009.html
總結(jié)
以上是生活随笔為你收集整理的【MySQL】可重复读模式下 unique key失效案例的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: protected private pu
- 下一篇: poj2718 Smallest Dif