最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

一文詳解MySQL不同隔離級(jí)別都使用什么鎖

 更新時(shí)間:2022年09月08日 08:56:10   作者:陳樹義  
這篇文章主要為大家詳細(xì)介紹了在MySQL中不同隔離級(jí)別都會(huì)使用什么鎖,文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)MySQL有一定幫助,需要的可以參考一下

在上篇文章,我們聊了「MySQL 啥時(shí)候會(huì)用表鎖,啥時(shí)候用行鎖」這個(gè)問(wèn)題。在文章中,我們還留了一個(gè)問(wèn)題,即:如果查詢或更新時(shí)的數(shù)據(jù)特別多,是否從行鎖會(huì)升級(jí)為表鎖?

此外,還有朋友留言說(shuō)到:不同的隔離級(jí)別可能會(huì)用不同的鎖,可以結(jié)合隔離級(jí)別來(lái)聊聊。其實(shí)上面雖然是兩個(gè)問(wèn)題,但如果你把不同隔離級(jí)別下的加鎖問(wèn)題搞清楚了,那么第一個(gè)問(wèn)題自然也清楚了。

今天,就讓我?guī)е蠹襾?lái)聊聊不同隔離級(jí)別下,都會(huì)使用什么鎖!

文章思維導(dǎo)圖

說(shuō)透 MySQL 鎖機(jī)制

在深入探討不同隔離級(jí)別的鎖內(nèi)容之前,我們需要先回顧一下關(guān)于 MySQL 鎖的本質(zhì)以及一些基礎(chǔ)內(nèi)容,這樣有利于我們后續(xù)的理解。

對(duì)于 MySQL 來(lái)說(shuō),如果只支持串行訪問(wèn)的話,那么其效率會(huì)非常低。因此,為了提高數(shù)據(jù)庫(kù)的運(yùn)行效率,MySQL 需要支持并發(fā)訪問(wèn)。

而在并發(fā)訪問(wèn)的情況下,會(huì)發(fā)生各種各樣的問(wèn)題,例如:臟讀、不可重復(fù)讀、幻讀等問(wèn)題。為了解決這些問(wèn)題,就出現(xiàn)了事務(wù)隔離級(jí)別。

本質(zhì)上,事務(wù)隔離級(jí)別就是為了解決并發(fā)訪問(wèn)下的數(shù)據(jù)一致性問(wèn)題的。不同的事務(wù)隔離級(jí)別,解決了不同程度的數(shù)據(jù)一致性。

而我們所說(shuō)的全局鎖、表鎖、行級(jí)鎖等等,其實(shí)都是事務(wù)隔離級(jí)別的具體實(shí)現(xiàn)。而 MVCC、意向鎖,則是一些局部的性能優(yōu)化。

上面這段話,基本上就是對(duì) MySQL 鎖機(jī)制很透徹的理解。當(dāng)我們懂了這些概念之間的關(guān)系之后,我們才能更加清晰地理解知識(shí)點(diǎn)。

事務(wù)隔離級(jí)別

相信大家都知道,MySQL 的事務(wù)隔離級(jí)別有如下 4 個(gè),分別是:

  • 讀未提交
  • 讀已提交(READ COMMITTED)
  • 可重復(fù)讀(REPEATABLE READ)
  • 串行化

讀未提交,可以讀取到其他事務(wù)還沒(méi)提交的數(shù)據(jù)。 在這個(gè)隔離級(jí)別下,由于可以讀取到未提交的值,因此會(huì)產(chǎn)生「臟讀」問(wèn)題。舉個(gè)例子:A 事務(wù)更新了 price 為 30,但還未提交。此時(shí) B 事務(wù)讀取到了 price 為 30,但后續(xù) A 事務(wù)回滾了,那么 B 事務(wù)讀取到的 price 就是錯(cuò)的(臟的)。

讀已提交,只能讀到其他事務(wù)已經(jīng)提交的數(shù)據(jù)。 這個(gè)隔離級(jí)別解決了臟讀的問(wèn)題,不會(huì)讀到未提交的值,但是卻會(huì)產(chǎn)生「不可重復(fù)讀」問(wèn)題?!覆豢芍貜?fù)讀」指的是在同一個(gè)事務(wù)范圍內(nèi),前后兩次讀取到的數(shù)據(jù)不一樣。舉個(gè)例子:A 事務(wù)第 1 次讀取了 price 為 10。

隨后 B 事務(wù)將 price 更新為 20,接著 A 事務(wù)再次讀取 price 為 30。A 事務(wù)前后兩次讀取到的數(shù)據(jù)是不一樣的,這就是不可重復(fù)讀。

思考題:MySQL 讀已提交可以解決臟讀問(wèn)題,那它具體是如何解決的?

可重復(fù)讀,指的是同一事務(wù)范圍內(nèi)讀取到的數(shù)據(jù)是一致的。 這個(gè)隔離級(jí)別解決了「不可重復(fù)讀」的問(wèn)題,只要是在同一事務(wù)范圍內(nèi),那么讀取到的數(shù)據(jù)就是一樣的。對(duì)于 MySQL Innodb 來(lái)說(shuō),其實(shí)通過(guò) MVCC 來(lái)實(shí)現(xiàn)的。但「可重復(fù)讀」隔離級(jí)別會(huì)產(chǎn)生幻讀問(wèn)題,即對(duì)于某個(gè)范圍的數(shù)據(jù)讀取,前后兩次可能讀取到不同的結(jié)果。

舉個(gè)例子:數(shù)據(jù)庫(kù)中有 price 為 1、3、5 三個(gè)商品,此時(shí) A 事務(wù)查詢 price < 10 的商品,查詢到了 3 個(gè)商品。隨后 B 事務(wù)插入了一條 price 為 7 的商品。接著 A 事務(wù)繼續(xù)查詢 price < 10 的商品,這次卻查詢到了 4 個(gè)商品。

可以看到「幻讀」與「不可重復(fù)讀」是有些類似的,只是「不可重復(fù)讀」更多指的是某一條記錄,而「幻讀」指的則是某個(gè)范圍數(shù)據(jù)。對(duì)于 MySQL Innodb 來(lái)說(shuō),其通過(guò)行級(jí)鎖級(jí)別的 Gap Lock 解決了幻讀的問(wèn)題。

串行化,指的是所有事務(wù)串行執(zhí)行。 這個(gè)就最簡(jiǎn)單了,不用去競(jìng)爭(zhēng),一個(gè)個(gè)去執(zhí)行,但是效率也是最低的。

MySQL 鎖類型

在 MySQL 中有全局鎖、表級(jí)鎖、行級(jí)鎖三種類型,其中比較關(guān)鍵的是表級(jí)鎖盒行級(jí)鎖。

對(duì)于表級(jí)鎖而言,其又分為表鎖、元數(shù)據(jù)鎖、意向鎖三種。對(duì)于元數(shù)據(jù)鎖而言,基本上都是數(shù)據(jù)庫(kù)自行操作,我們無(wú)須關(guān)心。在 Innodb 存儲(chǔ)存儲(chǔ)引擎中,表鎖也用得比較少。

對(duì)于行級(jí)鎖而言,其又記錄鎖、間隙鎖、Next-Key 鎖。記錄鎖就是某個(gè)索引記錄的鎖,間隙鎖就是兩個(gè)索引記錄之間的空隙鎖,Next-Key 則是前面兩者的結(jié)合。

在 Innodb 存儲(chǔ)引擎中,我們可以通過(guò)下面的命令來(lái)查詢鎖的情況。

//?開啟鎖的日志
set?global?innodb_status_output_locks=on;?
//?查看innodb引擎的信息(包含鎖的信息)
show?engine?innodb?status\G;

查詢結(jié)果一般如下圖所示:

上面幾種不同類型的鎖,其各自的關(guān)鍵字為:

  • 表級(jí)的意向排它鎖(IX):lock mode IX。
  • 表級(jí)的插入意向鎖(LOCK_INSERT_INTENTION): lock_mode X locks gap before rec insert intention
  • 行級(jí)的記錄鎖(LOCK_REC_NOT_GAP): lock_mode X locks rec but not gap
  • 行級(jí)的間隙鎖(LOCK_GAP): lock_mode X locks gap before rec
  • 行級(jí)的 Next-key 鎖(LOCK_ORNIDARY): lock_mode X

通過(guò)上面的命令,我們就可以知道不同的事務(wù)隔離級(jí)別使用了哪些鎖了。

接下來(lái),我們一個(gè)個(gè)來(lái)看看:不同事務(wù)隔離級(jí)別,都使用了哪些鎖來(lái)實(shí)現(xiàn)。

讀未提交

首先,我們創(chuàng)建一個(gè) price_test 表并插入一些測(cè)試數(shù)據(jù)。

//?創(chuàng)建?price_test?表
CREATE?TABLE?`test`.`price_test`?(
??`id`?BIGINT(64)?NOT?NULL?AUTO_INCREMENT,
??`name`?varchar(32)?not?null,
??`price`?INTEGER(4)?NULL,
??PRIMARY?KEY?(`id`));
//?插入測(cè)試數(shù)據(jù)
INSERT?INTO?price_test(name,price)?values('apple',?10);

接著,我們打開兩個(gè)命令行窗口,并且都修改事務(wù)隔離級(jí)別為「讀未提交」。

//?設(shè)置隔離級(jí)別
SET?session?TRANSACTION?ISOLATION?LEVEL?READ?UNCOMMITTED;
//?查看隔離級(jí)別
select?@@transaction_isolation;

接著,事務(wù) A 執(zhí)行如下命令,查詢出 id 為 1 記錄的 price 值。

//?執(zhí)行命令
beign;
select?*?from?price_test?where?id?=?1;
//?執(zhí)行結(jié)果
+----+-------+-------+
|?id?|?name??|?price?|
+----+-------+-------+
|??1?|?apple?|????10?|
+----+-------+-------+
1?row?in?set?(0.00?sec)

接著,事務(wù) B 執(zhí)行如下命令,修改 price 為 20。

begin;
update?price_test?set?price?=?20?where?id?=?1;

接著,事務(wù) A 再次讀取 id 為 1 記錄的 price 值。

select?*?from?price_test?where?id?=?1;

從下圖可以看到,事務(wù) A 讀取到了事務(wù) B 未提交的數(shù)據(jù),這其實(shí)就是臟讀了。

從這個(gè)例子,我們可以得出一些結(jié)論:在「讀未提交」事務(wù)隔離級(jí)別下,讀寫是可以同時(shí)進(jìn)行的,不會(huì)阻塞。

看到這里,我突然想到了一個(gè)問(wèn)題:那么寫寫是否會(huì)阻塞阻塞呢?

接下來(lái),我們繼續(xù)做一個(gè)測(cè)試:事務(wù) A 和 事務(wù) B 同時(shí)對(duì) id 為 1 的記錄進(jìn)行更新,看看是否能夠更新成功。

如上圖所示,我先用如下命令在事務(wù) A(上邊的窗口)執(zhí)行,將 price 修改為 15。

begin;
update?price_test?set?price?=?15?where?id?=?1;

結(jié)果執(zhí)行成功了,但此時(shí)事務(wù) A 還未提交。

接著,我先用如下命令在事務(wù) B(下邊的窗口)執(zhí)行,將 price 修改為 20。

從圖中可以看到,事務(wù) B 阻塞卡住了。

從這個(gè)例子,我們可以得出結(jié)論:在「讀未提交」事務(wù)隔離級(jí)別下,寫寫不可以同時(shí)進(jìn)行的,會(huì)阻塞。

此時(shí),我們通過(guò)查看鎖信息可以看到,其是加上一個(gè)行級(jí)別的記錄鎖,如下圖所示。

當(dāng)我使用 rollback 命令回滾事務(wù) A 之后,事務(wù) B 立刻就執(zhí)行了,并且事務(wù) A 還讀取到了事務(wù) B 設(shè)置的值,如下圖所示。

有些小伙伴會(huì)說(shuō):如果指定了非索引的列作為查詢條件,是否會(huì)觸發(fā)間隙鎖呢?

接下來(lái)我們測(cè)試一下。

我們往 price_test 表再插入一條數(shù)據(jù),此時(shí)數(shù)據(jù)庫(kù)中的數(shù)據(jù)如下所示。

接著,我們?cè)谑聞?wù) A 執(zhí)行如下命令,查詢 price > 15 的記錄。

mysql>?begin;
Query?OK,?0?rows?affected?(0.00?sec)
mysql>?select?*?from?price_test?where?price?>?15?for?update;
+----+--------+-------+
|?id?|?name???|?price?|
+----+--------+-------+
|??2?|?orange?|????30?|
+----+--------+-------+
1?row?in?set?(0.00?sec)

接著,我們?cè)谑聞?wù) B 執(zhí)行如下命令,查詢 price > 5 的記錄。

begin;
select?*?from?price_test?where?price?>?5?for?update;

從如下結(jié)果可以看到,事務(wù) B 阻塞住了。

此時(shí)我們?cè)谑聞?wù) A 查看鎖的情況,如下圖所示。

從上圖可以看出,MySQL 只是加上了一個(gè)記錄鎖,并沒(méi)有加間隙鎖。

最后我們總結(jié)一下:在「讀未提交」隔離級(jí)別下,讀寫操作可以同時(shí)進(jìn)行,但寫寫操作無(wú)法同時(shí)進(jìn)行。與此同時(shí),該隔離級(jí)別下只會(huì)使用行級(jí)別的記錄鎖,并不會(huì)用間隙鎖。

讀已提交

在「讀已提交」隔離級(jí)別下,我們按之前的方式進(jìn)行測(cè)試。

首先,我們?cè)O(shè)置一下隔離級(jí)別為「讀已提交」。

//?設(shè)置隔離級(jí)別
SET?session?TRANSACTION?ISOLATION?LEVEL?READ?COMMITTED;
//?查看隔離級(jí)別
select?@@transaction_isolation;

接著,我們測(cè)試同時(shí)對(duì) id 為 1 的數(shù)據(jù)進(jìn)行更新,看看會(huì)發(fā)生什么。

事務(wù) A 執(zhí)行如下命令:

begin;
update?price_test?set?price?=?15?where?id?=?1;

事務(wù) B 執(zhí)行如下命令

begin;
update?price_test?set?price?=?20?where?id?=?1;

事務(wù) B 阻塞了。查看下鎖信息,如下圖所示。

可以看到,其鎖是一個(gè)行級(jí)別的記錄鎖,結(jié)果和「讀未提交」的是一樣的。

接下來(lái),我們繼續(xù)看看范圍的查詢是否會(huì)觸發(fā)間隙鎖。

事務(wù) A 執(zhí)行:

begin;
select?*?from?price_test?where?price?>?5?for?update;

事務(wù) B 執(zhí)行:

begin;
select?*?from?price_test?where?price?>?15?for?update;

事務(wù) B 會(huì)阻塞,查看鎖信息如下圖所示。

可以看到,還是只有一個(gè)行級(jí)別的記錄鎖,并沒(méi)有間隙鎖。

看到這里,你會(huì)發(fā)現(xiàn)「讀已提交」和「讀未提交」非常相似。那么它們具體有啥區(qū)別呢?

其實(shí)他們的最大區(qū)別,就是「讀已提交」解決了臟讀的問(wèn)題。

可重復(fù)讀

在「讀已提交」隔離級(jí)別下,我們按之前的方式進(jìn)行測(cè)試。

首先,我們?cè)O(shè)置一下隔離級(jí)別為「讀已提交」。

//?設(shè)置隔離級(jí)別
SET?session?TRANSACTION?ISOLATION?LEVEL?REPEATABLE?READ;
//?查看隔離級(jí)別
select?@@transaction_isolation;

接著,我們測(cè)試同時(shí)對(duì) id 為 1 的數(shù)據(jù)進(jìn)行更新,看看會(huì)發(fā)生什么。

事務(wù) A 執(zhí)行如下命令:

begin;
update?price_test?set?price?=?15?where?id?=?1;

事務(wù) B 執(zhí)行如下命令

begin;
update?price_test?set?price?=?20?where?id?=?1;

事務(wù) B 阻塞了。查看下鎖信息,毫無(wú)疑問(wèn),其實(shí)這里還是只會(huì)有間隙鎖,因?yàn)橹付怂饕?/p>

接下來(lái),我們繼續(xù)看看范圍的查詢是否會(huì)觸發(fā)間隙鎖。

事務(wù) A 執(zhí)行:

begin;
select?*?from?price_test?where?price?>?5?for?update;

事務(wù) B 執(zhí)行:

begin;
select?*?from?price_test?where?price?>?15?for?update;

事務(wù) B 會(huì)阻塞,查看鎖信息如下圖所示。

可以看到,在這里就變成了 Next-Key 鎖,就是記錄鎖和間隙鎖結(jié)合體。

總結(jié)一下:在「可重復(fù)讀」隔離級(jí)別下,使用了記錄鎖、間隙鎖、Next-Key 鎖三種類型的鎖。

值得一提的是,我們前面說(shuō)過(guò):可重復(fù)讀存在幻讀的問(wèn)題,但實(shí)際上在 MySQL 中,因?yàn)槠涫褂昧碎g隙鎖,所以在「可重復(fù)讀」隔離級(jí)別下,其實(shí)不存在幻讀問(wèn)題。因此,MySQL 將「可重復(fù)讀」作為了其默認(rèn)的隔離級(jí)別。

總結(jié)

看到這里,我想我們可以對(duì)文章開頭提出的問(wèn)題做個(gè)解答了:MySQL 不同隔離級(jí)別,都使用了什么樣的鎖?

對(duì)于任何隔離級(jí)別,表級(jí)別的表鎖、元數(shù)據(jù)鎖、意向鎖都是會(huì)使用的,但對(duì)于行級(jí)別的鎖則會(huì)有些許差別。

在「讀未提交」和「讀已提交」隔離級(jí)別下,都只會(huì)使用記錄鎖,不會(huì)用間隙鎖,當(dāng)然也不會(huì)有 Next-Key 鎖了。

而對(duì)于「可重復(fù)讀」隔離級(jí)別來(lái)說(shuō),會(huì)使用記錄鎖、間隙鎖和 Next-Key 鎖。

到此這篇關(guān)于一文詳解MySQL不同隔離級(jí)別都使用什么鎖的文章就介紹到這了,更多相關(guān)MySQL隔離級(jí)別內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • MySQL修煉之聯(lián)結(jié)與集合淺析

    MySQL修煉之聯(lián)結(jié)與集合淺析

    在mysql中,最重要的就是查詢了,下面這篇文章主要給大家介紹了關(guān)于MySQL修煉之聯(lián)結(jié)與集合的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2021-09-09
  • MySQL存儲(chǔ)過(guò)程的傳參和流程控制示例講解

    MySQL存儲(chǔ)過(guò)程的傳參和流程控制示例講解

    這篇文章主要介紹了MySQL存儲(chǔ)過(guò)程的傳參和流程控制示例講解,?repeat和Loop區(qū)別是repeat有自己退出循環(huán)的語(yǔ)句until,Loop使用的是if判斷語(yǔ)句,本文結(jié)合示例代碼詳細(xì)講解,需要的朋友可以參考下
    2023-02-02
  • mysql grants小記

    mysql grants小記

    grant命令是對(duì)mysql數(shù)據(jù)庫(kù)進(jìn)行用戶創(chuàng)建,權(quán)限或其他參數(shù)控制的強(qiáng)大的命令,官網(wǎng)上介紹它就有幾大頁(yè),要用精它恐怕不是一日半早的事情,權(quán)宜根據(jù)心得慢慢領(lǐng)會(huì)吧!
    2011-05-05
  • 一次Mysql?update?sql不當(dāng)引起的生產(chǎn)故障記錄

    一次Mysql?update?sql不當(dāng)引起的生產(chǎn)故障記錄

    這篇文章主要給大家介紹了關(guān)于一次Mysql?update?sql不當(dāng)引起的生產(chǎn)故障的相關(guān)資料,由于update涉及到數(shù)據(jù)的修改,所以很容易推斷,update語(yǔ)句比select語(yǔ)句會(huì)更復(fù)雜一些,文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2022-04-04
  • MySQL 用 limit 為什么會(huì)影響性能

    MySQL 用 limit 為什么會(huì)影響性能

    對(duì)于小的偏移量,直接使用limit來(lái)查詢沒(méi)有什么問(wèn)題,但隨著數(shù)據(jù)量的增大,越往后分頁(yè),limit語(yǔ)句的偏移量就會(huì)越大,速度也會(huì)明顯變慢,接下來(lái)文章就向大家介紹其的原由,感興趣的小伙伴可參考下面文章具體內(nèi)容
    2021-09-09
  • mysql8.0使用PXC實(shí)現(xiàn)高可用

    mysql8.0使用PXC實(shí)現(xiàn)高可用

    本文主要介紹了mysql8.0使用PXC實(shí)現(xiàn)高可用,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2025-02-02
  • 阿里云配置MySQL-server?8.0遠(yuǎn)程登錄的實(shí)現(xiàn)

    阿里云配置MySQL-server?8.0遠(yuǎn)程登錄的實(shí)現(xiàn)

    我們經(jīng)常會(huì)碰到需要遠(yuǎn)程訪問(wèn)數(shù)據(jù)庫(kù)的場(chǎng)景,本文主要介紹了阿里云配置MySQL-server?8.0遠(yuǎn)程登錄的實(shí)現(xiàn),具有一定的參考價(jià)值,感興趣的可以了解一下
    2023-08-08
  • Mysql8.0修改配置文件my.ini的坑及解決

    Mysql8.0修改配置文件my.ini的坑及解決

    使用記事本直接編輯my.ini文件保存后,可能會(huì)導(dǎo)致MySQL無(wú)法啟動(dòng),因?yàn)镸ySQL會(huì)以ANSI編碼讀取該文件,解決方法是使用Notepad++打開my.ini文件,選擇ANSI編碼保存
    2025-01-01
  • MySQL Shell import_table數(shù)據(jù)導(dǎo)入的實(shí)現(xiàn)

    MySQL Shell import_table數(shù)據(jù)導(dǎo)入的實(shí)現(xiàn)

    這篇文章主要介紹了MySQL Shell import_table數(shù)據(jù)導(dǎo)入的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-08-08
  • MySQL重定位數(shù)據(jù)目錄的方法

    MySQL重定位數(shù)據(jù)目錄的方法

    這篇文章主要介紹了MySQL重定位數(shù)據(jù)目錄的實(shí)現(xiàn)方法,分析了重定位MySQL數(shù)據(jù)目錄的實(shí)現(xiàn)原理與技巧,具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2014-12-12

最新評(píng)論

独山县| 昌平区| 长治县| 泉州市| 富民县| 凤山县| 滦平县| 社旗县| 松溪县| 株洲县| 修武县| 永泰县| 汪清县| 伊吾县| 封开县| 和田县| 塔河县| 沧州市| 沈丘县| 明水县| 金坛市| 乌兰浩特市| 永济市| 镇巴县| 乌恰县| 会同县| 黄浦区| 栾城县| 靖西县| 阳城县| 灵丘县| 濉溪县| 北流市| 桃园市| 正镶白旗| 云龙县| 任丘市| 长治县| 阿城市| 乌拉特中旗| 上杭县|