欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

MySQL如何解決幻讀問(wèn)題

 更新時(shí)間:2021年08月06日 15:35:15   作者:JJian  
在高并發(fā)數(shù)據(jù)庫(kù)系統(tǒng)中,需要保證事務(wù)與事務(wù)之間的隔離性,還有事務(wù)本身的一致性。所以需要解決幻讀問(wèn)題,本文就來(lái)介紹一下,感興趣的可以了解一下

前言

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

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

  注:本博文討論的“幻讀”都是指在“可重復(fù)讀”隔離級(jí)別下進(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 t
VALUES (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è)),其它行不加鎖,那么就會(huì)出現(xiàn)如下場(chǎng)景:

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,此時(shí)表t中value=1的數(shù)據(jù)有兩行
  • T3:Q3返回兩行(0,0,1),(1,1,1)
  • T4:session C插入一行(6,6,1),此時(shí)表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)象,就稱之為幻讀,幻讀指的是一個(gè)事務(wù)在前后兩次查詢同一個(gè)范圍的時(shí)候,后一次查詢看到了前一次查詢沒(méi)有看到的行。

先對(duì)“幻讀”做出如下解釋:

  • 在可重復(fù)讀隔離級(jí)別下,普通的查詢是快照讀,是不會(huì)看到別的事務(wù)插入的數(shù)據(jù)的。因此, 幻讀在“當(dāng)前讀”下才會(huì)出現(xiàn)(三個(gè)查詢都是for update表示當(dāng)前讀);
  • 上面session B的修改update結(jié)果,被session A之后的select語(yǔ)句用“當(dāng)前讀”看到,不能稱為幻讀,幻讀僅專指“新插入的行”。

二、幻讀有什么問(wèn)題?

(1)需要單獨(dú)解決

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

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

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

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

三、如何解決幻讀?

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

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

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

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

  間隙鎖與間隙鎖之間是不存在沖突的,沖突的是往間隙里插入一條記錄?!?/p>

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

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

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

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

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

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

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

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

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

三、總結(jié)

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

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

相關(guān)文章

  • MySQL?系統(tǒng)變量(查看,修改)

    MySQL?系統(tǒng)變量(查看,修改)

    MySQL的系統(tǒng)變量是由MySQL服務(wù)器管理的,用于控制服務(wù)器的各種行為和特性,本文主要介紹了MySQL?系統(tǒng)變量(查看,修改),感興趣的可以了解一下
    2024-08-08
  • mysql5.7.19 winx64解壓縮版安裝配置教程

    mysql5.7.19 winx64解壓縮版安裝配置教程

    這篇文章主要為大家詳細(xì)介紹了mysql5.7.19 winx64解壓縮版安裝配置教程,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-07-07
  • 詳細(xì)聊聊MySQL中的LIMIT語(yǔ)句

    詳細(xì)聊聊MySQL中的LIMIT語(yǔ)句

    大家應(yīng)該都知道LIMIT子句可以被用于強(qiáng)制SELECT語(yǔ)句返回指定的記錄數(shù),這篇文章主要給大家介紹了關(guān)于MySQL中LIMIT語(yǔ)句的相關(guān)資料,需要的朋友可以參考下
    2021-10-10
  • MySQL 數(shù)據(jù)類型 大全

    MySQL 數(shù)據(jù)類型 大全

    mysql下的一些數(shù)據(jù)類型,后面附有類型的說(shuō)明。
    2009-04-04
  • 將json文件數(shù)據(jù)導(dǎo)入到MySQL表中的詳細(xì)教程

    將json文件數(shù)據(jù)導(dǎo)入到MySQL表中的詳細(xì)教程

    如何使用json文件將數(shù)據(jù)導(dǎo)入到MySQL數(shù)據(jù)庫(kù)中的表里?Excel表格等文件的數(shù)據(jù)通過(guò)java或者python等語(yǔ)言讀取后生成一個(gè)json文件,然后想要將文件中的數(shù)據(jù)寫入到MySQL表中,本文介紹了將json文件數(shù)據(jù)導(dǎo)入到MySQL表中的詳細(xì)教程,需要的朋友可以參考下
    2024-07-07
  • mysql+shardingSphere的分庫(kù)分表實(shí)現(xiàn)示例

    mysql+shardingSphere的分庫(kù)分表實(shí)現(xiàn)示例

    分庫(kù)分表是一種場(chǎng)景解決方案,它的出現(xiàn)是為了解決一些場(chǎng)景問(wèn)題的,本文主要介紹了mysql+shardingSphere的分庫(kù)分表實(shí)現(xiàn)示例,具有一定的參考價(jià)值,感興趣的可以
    2024-04-04
  • MySQL 獲得當(dāng)前日期時(shí)間 函數(shù)

    MySQL 獲得當(dāng)前日期時(shí)間 函數(shù)

    這篇文章主要介紹了MySQL 獲得當(dāng)前日期時(shí)間 函數(shù) 非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下
    2017-07-07
  • MySQL函數(shù)大全及用法示例分享

    MySQL函數(shù)大全及用法示例分享

    這篇文章主要介紹了MySQL的一些函數(shù)及用法示例,需要的朋友可以參考下
    2014-03-03
  • 如何修改mysql數(shù)據(jù)表主鍵

    如何修改mysql數(shù)據(jù)表主鍵

    這篇文章主要介紹了如何修改mysql數(shù)據(jù)表主鍵問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-07-07
  • MySQL 參數(shù)相關(guān)概念及查詢更改方法

    MySQL 參數(shù)相關(guān)概念及查詢更改方法

    這篇文章主要介紹了MySQL 參數(shù)相關(guān)概念及查詢更改方法,幫助大家更好的理解和使用MySQL數(shù)據(jù)庫(kù),感興趣的朋友可以了解下
    2020-09-09

最新評(píng)論