国产成人精品久久免费动漫-国产成人精品天堂-国产成人精品区在线观看-国产成人精品日本-a级毛片无码免费真人-a级毛片毛片免费观看久潮喷

您的位置:首頁技術(shù)文章
文章詳情頁

MySQL如何解決幻讀問題

瀏覽:102日期:2023-10-17 19:37:00
目錄前言一、什么是幻讀?二、幻讀有什么問題?(1)需要單獨解決(2)間隙鎖引發(fā)的并發(fā)度三、如何解決幻讀?三、總結(jié)前言

我們知道MySQL在可重復(fù)讀隔離級別下別的事物提交的內(nèi)容,是看不到的。而可提交隔離級別下是可以看到別的事務(wù)提交的。而如果我們的業(yè)務(wù)場景是在事物內(nèi)同樣的兩個查詢我們需要看到的數(shù)據(jù)都是一致的,不能被別的事物影響,就使用可重復(fù)讀隔離級別。這種情況下RR級別下的普通查詢(快照讀)依靠MVCC解決“幻讀”問題,如果是“當(dāng)前讀”的情況需要依靠什么解決“幻讀”問題呢?這就是本博文需要探討的。

在探討前可以看下之前的博文(MySQL是如何實現(xiàn)事務(wù)隔離?),主要介紹隔離級別的具體技術(shù)細(xì)節(jié),讀過以后看此篇文章可能更有幫助。

注:本博文討論的“幻讀”都是指在“可重復(fù)讀”隔離級別下進(jìn)行。

一、什么是幻讀?

假設(shè)我們有表t結(jié)構(gòu)如下,里面的初始數(shù)據(jù)行為:(0,0,0),(1,1,1),(2,2,2),(3,3,3),(4,4,4),(5,5,5)

CREATE TABLE `t`( `id` INT(11) NOT NULL, `key` INT(11) DEFAULT NULL, `value` INT(11) DEFAULT NULL, PRIMARY KEY (`id`), KEY `value` (`value`)) ENGINE = InnoDB;INSERT INTO tVALUES (0, 0, 0), (1, 1, 1), (2, 2, 2), (3, 3, 3), (4, 4, 4), (5, 5, 5)

假設(shè)select * from where value=1 for update,只在這一行加鎖(注意這只是假設(shè)),其它行不加鎖,那么就會出現(xiàn)如下場景:

MySQL如何解決幻讀問題

Session A的三次查詢Q1-Q3都是select * from where value=1 for update,查詢的value=1的所有row。

T1:Q1只返回一行(1,1,1); T2:session B更新id=0的value為1,此時表t中value=1的數(shù)據(jù)有兩行 T3:Q3返回兩行(0,0,1),(1,1,1) T4:session C插入一行(6,6,1),此時表t中value=1的數(shù)據(jù)有三行 T5:Q3返回三行(0,0,1),(1,1,1),(6,6,1) T6:session A事物commit。

其中Q3讀到value=1這一樣的現(xiàn)象,就稱之為幻讀,幻讀指的是一個事務(wù)在前后兩次查詢同一個范圍的時候,后一次查詢看到了前一次查詢沒有看到的行。

先對“幻讀”做出如下解釋:

在可重復(fù)讀隔離級別下,普通的查詢是快照讀,是不會看到別的事務(wù)插入的數(shù)據(jù)的。因此, 幻讀在“當(dāng)前讀”下才會出現(xiàn)(三個查詢都是for update表示當(dāng)前讀); 上面session B的修改update結(jié)果,被session A之后的select語句用“當(dāng)前讀”看到,不能稱為幻讀,幻讀僅專指“新插入的行”。二、幻讀有什么問題?(1)需要單獨解決

眾所周知,select ...for update語句就是將相應(yīng)的數(shù)據(jù)行鎖住,比如session A在T1時刻的Q1查詢語句:select * from where value=1 for update就是將value=1的數(shù)據(jù)行鎖住,但顯然如果是上述的場景發(fā)生,此時的for update語義被破壞了(并沒有鎖住value=1的數(shù)據(jù)行)。

即使把所有的記錄都加上鎖,還是阻止不了新插入的記錄,所以“幻讀”問題要單獨拿出來解決。沒法依靠MVCC或者行鎖機(jī)制來解決。這就引出“間隙鎖”,是另外一種加鎖機(jī)制。

(2)間隙鎖引發(fā)的并發(fā)度

間隙鎖引入以后,可能會導(dǎo)致同樣語句鎖住更大的范圍,這可能就會影響了并發(fā)度。具體請看下面介紹

三、如何解決幻讀?

產(chǎn)生幻讀的原因是,行鎖只能鎖住行,但是新插入記錄這個動作,要更新的是記錄之間的“間隙”。因此,為了解決幻讀問題,InnoDB只好引入新的鎖,也就是間隙鎖(Gap Lock)。

間隙:比如表中加入6個記錄,0,5,10,15,20,25。則產(chǎn)生7個間隙:

MySQL如何解決幻讀問題

在一行行掃描的過程中,不僅將給行加上了行鎖,還給行兩邊的空隙也加上了間隙鎖。這樣就確保了無法再插入新的記錄。

間隙鎖和行鎖合稱next-key lock,每個next-key lock是前開后閉區(qū)間(間隙鎖開區(qū)間,next-key lock前開后閉區(qū)間):

間隙鎖與間隙鎖之間是不存在沖突的,沖突的是往間隙里插入一條記錄。 

MySQL如何解決幻讀問題

表t中是沒有value=7這個數(shù)據(jù)的,所以Q1加的間隙鎖(1,5),而Q2也是加的這個間隙鎖,兩者不沖突都是為了保護(hù)這個間隙不允許插入值。

在表t初始化后,假設(shè)表的數(shù)據(jù)如下:

MySQL如何解決幻讀問題

如果用select * from for update執(zhí)行,則會把整個表所有記錄鎖起來,就形成了7個next-key lock,分別是(-∞,0]、(0,2]、(2,4]、(4,6]、(6,8]、(8, 10]、(10, +supremum]

間隙鎖的引入,可能會導(dǎo)致同樣的語句鎖住更大的范圍,是會影響了并發(fā)度

假設(shè)發(fā)生如下場景:

MySQL如何解決幻讀問題

 則明顯發(fā)生了死鎖,分析如下:

Q1:執(zhí)行select …for update語句,由于id=9這一行并不存在,因此會加上間隙鎖 (8,10); Q2:執(zhí)行select …for update語句,同樣會加上間隙鎖(8,10),間隙鎖之間不會沖突,因 此這個語句可以執(zhí)行成功; session B 試圖插入一行(9,9,9),被session A的間隙鎖擋住了,只好進(jìn)入等待; session A試圖插入一行(9,9,9),被session B的間隙鎖擋住了。

有上述可知間隙鎖的引入,可能會導(dǎo)致同樣語句鎖住更大的范圍,這其實是影響了并發(fā)度。

為了解決幻讀問題可以采用讀可提交隔離級別,間隙鎖是在可重復(fù)讀隔離級別下才會生效的。所以如果把隔離級別設(shè)置為讀提交的話, 就沒有間隙鎖了。但同時,你要解決可能出現(xiàn)的數(shù)據(jù)和日志不一致問題,需要把binlog格式設(shè)置為row,也就是說采用“RC隔離級別+日志格式binlog_format=row”組合。

三、總結(jié) RR隔離級別下間隙鎖才有效,RC隔離級別下沒有間隙鎖; RR隔離級別下為了解決“幻讀”問題:“快照讀”依靠MVCC控制,“當(dāng)前讀”通過間隙鎖解決; 間隙鎖和行鎖合稱next-key lock,每個next-key lock是前開后閉區(qū)間; 間隙鎖的引入,可能會導(dǎo)致同樣語句鎖住更大的范圍,影響并發(fā)度。

到此這篇關(guān)于MySQL如何解決幻讀問題的文章就介紹到這了,更多相關(guān)MySQL 幻讀內(nèi)容請搜索好吧啦網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持好吧啦網(wǎng)!

標(biāo)簽: MySQL 數(shù)據(jù)庫
相關(guān)文章:
主站蜘蛛池模板: 最新99国产成人精品视频免费 | 91理论片午午伦夜理片久久 | 69成人做爰视频在线观看 | 99国产精品视频久久久久 | 国产美女作爱视频 | 在线观看亚洲人成网站 | 美女插跳蛋视频叫爽 | 欧美大陆日韩 | 成人a在线 | 亚洲男人的天堂在线 | 国产成人深夜福利在线观看 | 欧美一区二区日韩一区二区 | 久久在线免费观看 | 一级国产a级a毛片无卡 | 毛片成人 | 伊人久爱 | 四色6677最新永久网站 | 国产乱淫a∨片免费视频 | 毛片在线视频在线播放 | 欧美成人免费在线视频 | 久久精品毛片 | 欧美日韩一区二区综合 | 国产原创系列在线 | 美女又黄又免费 | 欧美日本一区二区三区道 | 免费人成在线观看 | 成人综合影院 | 成人a毛片视频免费看 | 三级毛片基地 | 欧美一级精品 | 成熟性xxxxx 成网站在线观看人免费 | 亚洲理论片在线观看 | av毛片在线看 | 免费嗨片 | 仑乱高清在线一级播放 | 久久精品观看 | 男同黄网站 | 国产性自爱拍偷在在线播放 | 最新步兵社区在线观看 | 成人做爰网站免费看 | 日本红怡院亚洲红怡院最新 |