日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

保姆级教程,终于搞懂脏读、幻读和不可重复读了!(经典回顾)

發布時間:2025/3/11 编程问答 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 保姆级教程,终于搞懂脏读、幻读和不可重复读了!(经典回顾) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

作者 | 王磊

來源 | Java中文社群(ID:javacn666)

轉載請聯系授權(微信ID:GG_Stone)

我的文章合集:https://gitee.com/mydb/interview

在 MySQL 中事務的隔離級別有以下 4 種:

  • 讀未提交(READ UNCOMMITTED)

  • 讀已提交(READ COMMITTED)

  • 可重復讀(REPEATABLE READ)

  • 序列化(SERIALIZABLE)

  • MySQL 默認的事務隔離級別是可重復讀(REPEATABLE READ),這 4 種隔離級別的說明如下。

    1.READ UNCOMMITTED

    讀未提交,也叫未提交讀,該隔離級別的事務可以看到其他事務中未提交的數據。該隔離級別因為可以讀取到其他事務中未提交的數據,而未提交的數據可能會發生回滾,因此我們把該級別讀取到的數據稱之為臟數據,把這個問題稱之為臟讀。

    2.READ COMMITTED

    讀已提交,也叫提交讀,該隔離級別的事務能讀取到已經提交事務的數據,因此它不會有臟讀問題。但由于在事務的執行中可以讀取到其他事務提交的結果,所以在不同時間的相同 SQL 查詢中,可能會得到不同的結果,這種現象叫做不可重復讀。

    3.REPEATABLE READ

    可重復讀,是 MySQL 的默認事務隔離級別,它能確保同一事務多次查詢的結果一致。但也會有新的問題,比如此級別的事務正在執行時,另一個事務成功的插入了某條數據,但因為它每次查詢的結果都是一樣的,所以會導致查詢不到這條數據,自己重復插入時又失敗(因為唯一約束的原因)。明明在事務中查詢不到這條信息,但自己就是插入不進去,這就叫幻讀 (Phantom Read)。

    4.SERIALIZABLE

    序列化,事務最高隔離級別,它會強制事務排序,使之不會發生沖突,從而解決了臟讀、不可重復讀和幻讀問題,但因為執行效率低,所以真正使用的場景并不多。

    簡單總結一下,MySQL 的 4 種事務隔離級別對應臟讀、不可重復讀和幻讀的關系如下:

    事務隔離級別臟讀不可重復讀幻讀
    讀未提交(READ UNCOMMITTED)
    讀已提交(READ COMMITTED)×
    可重復讀(REPEATABLE READ)××
    串行化(SERIALIZABLE)×××

    只看以上概念會比較抽象,接下來,咱們一步步通過執行的結果來理解這幾種隔離級別的區別。

    前置知識

    1.事務相關的常用命令

    #?查看?MySQL?版本 select?version();#?開啟事務 start?transaction;#?提交事務 commit;#?回滾事務 rollback;

    2.MySQL 8 之前查詢事務的隔離級別

    查看全局 MySQL 事務隔離級別和當前會話的事務隔離級別的 SQL 如下:

    select?@@global.tx_isolation,@@tx_isolation;

    以上 SQL 執行結果如下圖所示:

    3.MySQL 8 之后查詢事務的隔離級別

    select?@@global.transaction_isolation,@@transaction_isolation;

    4.查看連接的客戶端詳情

    每個 MySQL 命令行窗口就是一個 MySQL 客戶端,每個客戶端都可以單獨設置(不同的)事務隔離級別,這也是演示 MySQL 并發事務的基礎。以下是查詢客戶端連接的 SQL 命令:

    show?processlist;

    以上 SQL 執行結果如下:

    5.查詢連接客戶端的數量

    可以使用以下 SQL 命令,查詢連當前接 MySQL 服務器的客戶端數量:

    show?status?like?'Threads%';

    以上 SQL 執行結果如下:

    6.設置客戶端的事務隔離級別

    通過以下 SQL 可以設置當前客戶端的事務隔離級別:

    set?session?transaction?isolation?level?事務隔離級別;

    事務隔離級別的值有 4 個:READ UNCOMMITTED、READ COMMITTED、REPEATABLE READ、SERIALIZABLE。

    7.新建數據庫和測試數據

    創建測試數據庫和表信息,執行 SQL 如下:

    --?創建數據庫 drop?database?if?exists?testdb; create?database?testdb; use?testdb; --?創建表 create?table?userinfo(id?int?primary?key?auto_increment,name?varchar(250)?not?null,balance?decimal(10,2)?not?null?default?0 ); --?插入測試數據 insert?into?userinfo(id,name,balance)?values(1,'Java',100),(2,'MySQL',200);

    創建的表結構和數據如下:

    8.名稱約定

    接下來會使用兩個窗口(兩個客戶端)來演示事務不同隔離級別中臟讀、不可重復讀和幻讀的問題。其中左邊的黑底綠字的客戶端下文將使用“窗口 1”來指代,而右邊的藍底白字的客戶端下文將用“窗口 2”來指代,如下圖所示:

    臟讀

    一個事務讀到另外一個事務還沒有提交的數據,稱之為臟讀。臟讀演示的執行流程如下:

    執行步驟客戶端1(窗口1)客戶端2(窗口2)說明
    第 1 步
    set session transaction isolation level read uncommitted;
    start transaction;
    select * from userinfo;
    設置事務隔離級別為讀未提交;
    開啟事務;
    查詢用戶列表,其中 Java 用戶的余額為 100 元。
    第 2 步start transaction;
    update userinfo set balance=balance+50 where name='Java';

    開啟事務;
    給 Java 用戶的賬戶加 50 元;
    第 3 步
    select * from userinfo;查詢用戶列表,其中 Java 用戶的余額變成了 150 元。

    臟讀演示步驟1

    設置窗口 2 的事務隔離級別為讀未提交,設置命令如下:

    set?session?transaction?isolation?level?read?uncommitted;

    PS:事務隔離級別讀未提交存在臟讀的問題。

    然后使用命令來檢查當前連接窗口的事務隔離界別,如下圖所示:開啟事務并查詢用戶列表信息,如下圖所示:

    臟讀演示步驟2

    在窗口 1 中開啟一個事務,并給 Java 賬戶加 50 元,但不提交事務,執行的 SQL 如下:

    臟讀演示步驟3

    在窗口 2 中再次查詢用戶列表,執行結果如下:從上述結果可以看出,在窗口 2 中讀取到了窗口 1 中事務未提交的數據,這就是臟讀。

    不可重復讀

    不可重復讀是指一個事務先后執行同一條 SQL,但兩次讀取到的數據不同,就是不可重復讀。不可重復讀演示的執行流程如下:

    執行步驟客戶端1(窗口1)客戶端2(窗口2)說明
    第 1 步
    set session transaction isolation level read committed;
    start transaction;
    select * from userinfo;
    設置事務隔離級別為讀已提交;
    開啟事務;
    查詢用戶列表,其中 Java 用戶的余額是 100 元。
    第 2 步start transaction;update userinfo set balance=balance+20 where name='Java';commit;
    開啟事務;
    給 Java 用戶的余額加 20 元;提交事務。
    第 3 步
    select * from userinfo;查詢用戶列表,其中 Java 用戶的余額變成了 120 元。

    窗口 2 同一個事務中的兩次查詢,得到了不同的結果這就是不可重復讀,具體執行步驟如下。

    不可重復讀演示步驟1

    設置窗口 2 的事務隔離級別為讀已提交,設置命令如下:

    set?session?transaction?isolation?level?read?committed;

    PS:讀已提交可以解決臟讀的問題,但存在不可重復讀的問題。

    使用命令來檢查當前連接窗口的事務隔離界別,如下圖所示:在窗口 2 中開啟事務,并查詢用戶表,執行結果如下:此時查詢的列表中,Java 用戶的余額為 100 元。

    不可重復讀演示步驟2

    在窗口 1 中開啟事務,并給 Java 用戶添加 20 元,但不提交事務,再觀察窗口 2 中有沒有臟讀的問題,具體執行結果如下圖所示:從上述結果可以看出,當把窗口的事務隔離級別設置為讀已提交,已經不存在臟讀問題了。接下來在窗口 1 中提交事務,執行結果如下圖所示:

    不可重復讀演示步驟3

    切換到窗口 2 中再次查詢用戶列表,執行結果如下:從上述結果可以看出,此時 Java 用戶的余額已經變成 120 元了。在同一個事務中,先后查詢的兩次結果不一致就是不可重復讀。

    不可重復讀和臟讀的區別

    臟讀可以讀到其他事務中未提交的數據,而不可重復讀是讀取到了其他事務已經提交的數據,但前后兩次讀取的結果不同。

    幻讀

    幻讀名如其文,它就像發生了某種幻覺一樣,在一個事務中明明沒有查到主鍵為 X 的數據,但主鍵為 X 的數據就是插入不進去,就像某種幻覺一樣。幻讀演示的執行流程如下:

    執行步驟客戶端1(窗口1)客戶端2(窗口2)說明
    第 1 步
    set session transaction isolation level repeatable read;
    start transaction;
    select * from userinfo where id=3;
    設置事務隔離級別為可重復讀;
    開啟事務;
    查詢用戶編號為 3 的數據,查詢結果為空。
    第 2 步start transaction;
    insert into userinfo(id,name,balance) values(3,'Spring',100);
    commit;

    開啟事務;
    添加用戶,用戶編號為 3;
    提交事務。
    第 3 步
    insert into userinfo(id,name,balance) values(3,'Spring',100);窗口 2 添加用戶編號為 3 的數據,執行失敗。
    第 4 步
    select * from userinfo where id=3;查詢用戶編號為 3 的數據,查詢結果為空。

    具體執行結果如下步驟所示。

    幻讀演示步驟1

    設置窗口 2 為可重復讀,可重復有幻讀的問題,查詢編號為 3 的用戶,具體執行 SQL 如下:

    set?session?transaction?isolation?level?repeatable?read; start?transaction; select?*?from?userinfo?where?id=3;

    以上 SQL 執行結果如下圖所示:從上述結果可以看出,查詢的結果中 id=3 的數據為空。

    幻讀演示步驟2

    開啟窗口 1 的事務,插入用戶編號為 3 的數據,然后成功提交事務,執行 SQL 如下:

    start?transaction; insert?into?userinfo(id,name,balance)?values(3,'Spring',100); commit;

    以上 SQL 執行結果如下圖所示:

    幻讀演示步驟3

    在窗口 2 中插入用戶編號為 3 的數據,執行 SQL 如下:

    insert?into?userinfo(id,name,balance)?values(3,'Spring',100);

    以上 SQL 執行結果如下圖所示:添加用戶數據失敗,提示表中已經存在了編號為 3 的數據,且此字段為主鍵,不能添加多個。

    幻讀演示步驟4

    在窗口 2 中,重新執行查詢:

    select?*?from?userinfo?where?id=3;

    以上 SQL 執行結果如下圖所示:/ 在此事務中查詢明明沒有編號為 3 的用戶,但插入的時候卻卻提示已經存在了,這就是幻讀。

    不可重復讀和幻讀的區別

    二者描述的則重點不同,不可重復讀描述的側重點是修改操作,而幻讀描述的側重點是添加和刪除操作。

    總結

    本文演示了 MySQL 的 4 種事務隔離級別:讀未提交(有臟讀問題)、讀已提交(有不可重復讀的問題)、可重復讀(有幻讀的問題)和序列化,其中可重復讀是 MySQL 默認的事務隔離級別。臟讀是讀到了其他事務未提交的數據,而不可重復讀是讀到了其他事務已經提交的數據,但前后查詢的結果不同,而幻讀則是明明查詢不到,但就是插入不了。

    是非審之于己,毀譽聽之于人,得失安之于數。?

    公眾號:Java面試真題解析

    總結

    以上是生活随笔為你收集整理的保姆级教程,终于搞懂脏读、幻读和不可重复读了!(经典回顾)的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。