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

MySQL在讀已提交和可重復讀這兩個不同事務隔離級別下幻讀的區(qū)別及說明

 更新時間:2025年06月30日 15:55:28   作者:yuhuofei2021  
這篇文章主要介紹了MySQL在讀已提交和可重復讀這兩個不同事務隔離級別下幻讀的區(qū)別及說明,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教

1. 前 言

在正式開始之前,先簡單回顧一下并發(fā)事務存在的問題以及事務的隔離級別等內(nèi)容。

1.1 并發(fā)事務存在的問題

當兩個或者兩個以上事務同時開啟去處理同一個表的數(shù)據(jù)時,可能會存在以下的問題:

  • 丟失修改
  • 臟讀
  • 不可重復讀
  • 幻讀

丟失修改

丟失修改是指當兩個或多個事務更新同一行記錄,產(chǎn)生更新丟失的現(xiàn)象,事務回滾覆蓋和事務提交覆蓋都會導致這種現(xiàn)象的產(chǎn)生。

臟讀

一個事務能讀取到另一個事務已經(jīng)修改但還沒有提交的數(shù)據(jù)。

不可重復讀

在一個事務中多次執(zhí)行同一條查詢語句,讀取到的數(shù)據(jù)內(nèi)容前后不一致。

幻讀

在一個事務中多次執(zhí)行同一條查詢語句,讀取到的數(shù)據(jù)記錄在數(shù)量上前后不一致,可能多了幾條記錄也可能少了幾條記錄。

1.2 事務的隔離級別

為了解決并發(fā)事務存在的問題,大佬們想到了一個手段,那就是對事務進行隔離,最好是做到各個事務各干各的,互不干涉,但理想很豐滿,現(xiàn)實很骨感,哪可能一步到位呢。

為了應對不同的需要,解決不同的問題,于是決定將事務的隔離分成四個級別,分別是:

  • 讀未提交
  • 讀已提交
  • 可重復讀
  • 串行化

它們各自能解決的并發(fā)事務問題如下表所示:

隔離級別 \ 事務問題事務回滾覆蓋臟讀不可重復讀事務提交覆蓋幻讀
讀未提交能解決不能解決不能解決不能解決不能解決
讀已提交能解決能解決不能解決不能解決不能解決
可重復讀能解決能解決能解決能解決不能完全解決,可能發(fā)生
串行化能解決能解決能解決能解決能解決

1.3 快照讀和當前讀

快照讀

快照讀是基于 MVCC 和 undo log 來實現(xiàn)的,讀取數(shù)據(jù)的歷史版本,得到一個 ReadView (事務視圖) ,不對數(shù)據(jù)加鎖,適用于簡單 select 語句。

這里提一句,所謂 MVCC 并發(fā)版本控制,就是靠 ReadView (事務視圖) 來實現(xiàn)的,多個 readView 組成 undo log(回滾日志)。

當前讀

當前讀是基于行鎖 + 間隙鎖來實現(xiàn)的,讀取數(shù)據(jù)的最新版本,并對數(shù)據(jù)進行加鎖,適用于 insertupdate,deleteselect ... for update, select ... lock in share mode語句,以及加鎖了的 select 語句。

在更新數(shù)據(jù)時,都是先讀后寫,而這個讀,就是指當前讀,意味讀取數(shù)據(jù)時,讀到的是該條數(shù)據(jù)最新生成的 ReadView。

2. 不同事務隔離級別下幻讀的區(qū)別

在上面的表格中,我們能看到,在讀已提交這個隔離級別下,幻讀是不能被解決的,也就是說會發(fā)生;而在可重復讀這個隔離級別下,幻讀則是沒有完全被解決,只是解決了部分,意味著仍然有可能發(fā)生。

那它們分別是怎么產(chǎn)生的?各自又有什么表現(xiàn)?有何區(qū)別?下面我們舉個例子來探究一下。

假設(shè)現(xiàn)在有兩個事務,分別是事務 A 和 事務 B ,同時有一張學生表 student(表中只有一條記錄,stu_name 為王大) ,我們用這兩個事務來操作這張表。

2.1 讀已提交下的幻讀

在讀已提交這種事務隔離級別下,兩個事務的操作順序如下:

事務A事務B
begin;begin;
開始第一次查詢:select * from student where stu_id > 0;insert into student(stu_name) values(‘李二’);
開始第二次查詢:select * from student where stu_id > 0;commit;
  1. 事務 A 第一次查詢,得到的數(shù)據(jù)記錄是 stu_name 為王大這一條
  2. 事務 B 中途往表里插入了一條 stu_name 為李二的記錄,并提交自身的事務
  3. 事務 A 用第一次查詢的 SQL 語句進行第二次查詢時,發(fā)現(xiàn)得到的數(shù)據(jù)記錄成了兩條,出現(xiàn)幻讀

表現(xiàn)

普通的查詢語句,能看到明顯幻讀現(xiàn)象。

原因剖析

事務 A 中用的是普通的 select 語句,因此采用的是快照讀,但由于事務隔離級別為讀已提交,在讀已提交下,每次 select 操作,都會重新獲取最新版本的數(shù)據(jù),也正是因為這個原因,導致事務 A 中兩次查詢得到的結(jié)果在數(shù)量不一致,產(chǎn)生幻讀。

解決方式

將事務隔離級別升級為可重復讀

2.2 可重復讀下的幻讀

2.2.1 情況一,無幻讀

在可重復讀這種事務隔離級別下,兩個事務的操作順序如下:

事務A事務B
begin;begin;
開始第一次查詢:select * from student where stu_id > 0;insert into student(stu_name) values(‘李二’);
開始第二次查詢:select * from student where stu_id > 0;commit;

像上面這樣的事務操作,雖然在讀已提交事務隔離級別下會產(chǎn)生幻讀,但在可重復讀事務隔離級別下,卻不會產(chǎn)生幻讀。

原因:在可重復讀事務隔離級別下,針對普通的 select 語句,采用的是快照讀,只會在第一次查詢的時候獲取一次數(shù)據(jù)的版本,往后繼續(xù)做相同的 select 操作,不會重新獲取,會延用前面得到的數(shù)據(jù)版本。

細心的你有沒有發(fā)現(xiàn),在可重復讀事務隔離級別下,對于快照讀(普通的 select 操作),這不就是使用 MVCC 解決幻讀問題嗎?你沒看錯,是這樣的。

2.2.2 情況二,有幻讀

在可重復讀這種事務隔離級別下,兩個事務的操作順序如下:

事務A事務B
begin;begin;
開始第一次查詢:select * from student where stu_id > 0;insert into student(stu_name) values(‘李二’);
開始第二次查詢:select * from student where stu_id > 0 for update;commit;

上面的事務操作,和前面不同的地方在于,第二次查詢加上了 for update ,也就是采用當前讀。

表現(xiàn)

能看到明顯的幻讀現(xiàn)象

原因剖析

由于事務 A 第二次查詢在 SQL 語句末尾加上了 for update ,表示采用當前讀的方式,獲取數(shù)據(jù)的最新版本,那么自然而然會把事務 B 中途插入的數(shù)據(jù)給查出來,從而出現(xiàn)幻讀。

解決方式

用 next-key lock 解決,如果是走索引,會鎖住索引本身的行鎖;如果是范圍,就會成為一個行鎖+間隙鎖,導致范圍內(nèi)的無法插入;如果是無索引的,直接全表加上了間隙鎖,無法插入,阻塞。

具體的操作方式如下:

事務A事務B
begin;begin;
開始第一次查詢:select * from student where stu_id > 0 for update;insert into student(stu_name) values(‘李二’);
開始第二次查詢:select * from student where stu_id > 0 for update;commit;

事務 A 的每次查詢都加上 for update,這樣就不會出現(xiàn)幻讀,原因是事務 B 的 insert 操作會被阻塞,無法將數(shù)據(jù)插入到表中,從而避免幻讀的出現(xiàn)。

2.2.3 情況三,有幻讀

在可重復讀這種事務隔離級別下,兩個事務的操作順序如下:

事務A事務B
begin;begin;
開始第一次查詢:select * from student where stu_id > 0;insert into student(stu_name) values(‘李二’);
update student set stu_class = ‘03’ where stu_id is not null;commit;
開始第二次查詢:select * from student where stu_id > 0;

在上面的事務操作下,事務 B 能將數(shù)據(jù)記錄正常插入到表中,而事務 A 做了一次 update 操作,從上面的介紹我們可以知道,update 操作是當前讀,會獲取到數(shù)據(jù)的最新版本,自然也能拿到事務 B 的提交記錄。

表現(xiàn)

能明顯看到幻讀現(xiàn)象

原因剖析

事務 A 的 update 操作采用的是當前讀,會獲取數(shù)據(jù)的最新版本,將事務 B 提交的結(jié)果讀取出來,后面事務 A 再做普通的 select 操作,采用快照讀,由于延用 update 操作時得到的數(shù)據(jù)歷史版本,因而產(chǎn)生幻讀。

解決方式

同 2.2.2 中的解決方式一樣,具體操作如下:

事務A事務B
begin;begin;
開始第一次查詢:select * from student where stu_id > 0 for update;insert into student(stu_name) values(‘李二’);
update student set stu_class = ‘03’ where stu_id is not null;commit;
開始第二次查詢:select * from student where stu_id > 0 for update;

最簡單的解決方式,就是再將事務隔離級別升級,改為串行化,畢竟串行化本身就解決所有事務問題,當然,這會犧牲效率。

總結(jié)

并發(fā)事務中,對于普通的 select 語句,在讀已提交下,能明顯看到幻讀的現(xiàn)象,而在可重復讀下,看不到幻讀現(xiàn)象。

并發(fā)事務中,對于事務執(zhí)行語句里含有當前讀的情況,得具體問題具體分析,可能可以看到幻讀,也可能由于加了 for update ,看不到幻讀。

以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • mysql去重的兩種方法詳解及實例代碼

    mysql去重的兩種方法詳解及實例代碼

    這篇文章主要介紹了mysql去重的兩種方法詳解及實例代碼的相關(guān)資料,這里對去重的兩種方法進行了一一實例詳解,需要的朋友可以參考下
    2017-01-01
  • mysql 5.6 從陌生到熟練之_數(shù)據(jù)庫備份恢復的實現(xiàn)方法

    mysql 5.6 從陌生到熟練之_數(shù)據(jù)庫備份恢復的實現(xiàn)方法

    下面小編就為大家?guī)硪黄猰ysql 5.6 從陌生到熟練之_數(shù)據(jù)庫備份恢復的實現(xiàn)方法。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2016-10-10
  • MySQL Antelope和Barracuda的區(qū)別分析

    MySQL Antelope和Barracuda的區(qū)別分析

    這篇文章主要介紹了MySQL Antelope和Barracuda的區(qū)別分析,Antelope和Barracude都是一種文件格式,需要的朋友可以參考下
    2014-07-07
  • MySQL庫與表的DDL核心操作實戰(zhàn)案例

    MySQL庫與表的DDL核心操作實戰(zhàn)案例

    本文詳細介紹了MySQL數(shù)據(jù)庫和表的創(chuàng)建、修改、備份、刪除等操作,涵蓋了字符集選擇、表結(jié)構(gòu)設(shè)計、備份恢復等核心知識點,通過實際案例,讀者可以掌握精準操作,避免數(shù)據(jù)丟失,提升開發(fā)效率,感興趣的朋友跟隨小編一起看看吧
    2026-03-03
  • MySQL 5.7 mysql command line client 使用命令詳解

    MySQL 5.7 mysql command line client 使用命令詳解

    這篇文章主要介紹了MySQL 5.7 mysql command line client 使用命令,需要的朋友可以參考下
    2017-06-06
  • MySQL創(chuàng)建數(shù)據(jù)庫并支持中文字符的操作方法

    MySQL創(chuàng)建數(shù)據(jù)庫并支持中文字符的操作方法

    這篇文章主要介紹了MySQL創(chuàng)建數(shù)據(jù)庫并支持中文字符的操作方法,本文給大家介紹的非常詳細,對大家的學習或工作具體一定的參考借鑒價值,需要的朋友可以參考下
    2021-01-01
  • mysql執(zhí)行計劃id為空(UNION關(guān)鍵字)詳解

    mysql執(zhí)行計劃id為空(UNION關(guān)鍵字)詳解

    這篇文章主要給大家介紹了關(guān)于mysql執(zhí)行計劃id為空(UNION關(guān)鍵字)的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2018-09-09
  • MySql庫與表的基礎(chǔ)操作大全

    MySql庫與表的基礎(chǔ)操作大全

    本文詳細講解了MySQL數(shù)據(jù)庫與表的核心操作,掌握這些基礎(chǔ)操作后,可進一步學習MySQL的索引優(yōu)化、事務管理等高級知識,提升數(shù)據(jù)庫操作的效率與安全性,感興趣的朋友跟隨小編一起看看吧
    2025-10-10
  • MySQL字段為 NULL的5大坑

    MySQL字段為 NULL的5大坑

    本文主要介紹了MySQL字段為 NULL的5大坑,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2023-04-04
  • CentOS7.x?安裝mysql5.7?XtraBackUp備份工具使用命令詳解

    CentOS7.x?安裝mysql5.7?XtraBackUp備份工具使用命令詳解

    這篇文章主要介紹了CentOS7.x?安裝mysql5.7?XtraBackUp備份工具使用,本文給大家介紹了mysql安裝過程及命令使用方法,需要的朋友可以參考下
    2022-04-04

最新評論

张家口市| 潞西市| 荣昌县| 江西省| 左贡县| 会东县| 波密县| 石屏县| 余干县| 鸡西市| 佳木斯市| 株洲县| 旌德县| 盐山县| 萨迦县| 沈丘县| 绥芬河市| 杭锦后旗| 灵武市| 兴业县| 凉山| 布尔津县| 临沂市| 通化市| 大邑县| 南乐县| 康马县| 延寿县| 阿合奇县| 康乐县| 丰顺县| 池州市| 揭西县| 延吉市| 六枝特区| 突泉县| 鹤壁市| 石渠县| 互助| 儋州市| 南华县|