自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

保姆級教程,終于搞懂臟讀、幻讀和不可重復(fù)讀了!

數(shù)據(jù)庫 MySQL
本文演示了 MySQL 的 4 種事務(wù)隔離級別:讀未提交(有臟讀問題)、讀已提交(有不可重復(fù)讀的問題)、可重復(fù)讀(有幻讀的問題)和序列化,其中可重復(fù)讀是 MySQL 默認(rèn)的事務(wù)隔離級別。

作者 | 王磊

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

轉(zhuǎn)載請聯(lián)系授權(quán)(微信ID:GG_Stone)

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

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

  1. 讀未提交(READ UNCOMMITTED)
  2. 讀已提交(READ COMMITTED)
  3. 可重復(fù)讀(REPEATABLE READ)
  4. 序列化(SERIALIZABLE)

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

1.READ UNCOMMITTED

讀未提交,也叫未提交讀,該隔離級別的事務(wù)可以看到其他事務(wù)中未提交的數(shù)據(jù)。該隔離級別因?yàn)榭梢宰x取到其他事務(wù)中未提交的數(shù)據(jù),而未提交的數(shù)據(jù)可能會發(fā)生回滾,因此我們把該級別讀取到的數(shù)據(jù)稱之為臟數(shù)據(jù),把這個問題稱之為臟讀。

2.READ COMMITTED

讀已提交,也叫提交讀,該隔離級別的事務(wù)能讀取到已經(jīng)提交事務(wù)的數(shù)據(jù),因此它不會有臟讀問題。但由于在事務(wù)的執(zhí)行中可以讀取到其他事務(wù)提交的結(jié)果,所以在不同時間的相同 SQL 查詢中,可能會得到不同的結(jié)果,這種現(xiàn)象叫做不可重復(fù)讀。

3.REPEATABLE READ

可重復(fù)讀,是 MySQL 的默認(rèn)事務(wù)隔離級別,它能確保同一事務(wù)多次查詢的結(jié)果一致。但也會有新的問題,比如此級別的事務(wù)正在執(zhí)行時,另一個事務(wù)成功的插入了某條數(shù)據(jù),但因?yàn)樗看尾樵兊慕Y(jié)果都是一樣的,所以會導(dǎo)致查詢不到這條數(shù)據(jù),自己重復(fù)插入時又失敗(因?yàn)槲ㄒ患s束的原因)。明明在事務(wù)中查詢不到這條信息,但自己就是插入不進(jìn)去,這就叫幻讀 (Phantom Read)。

4.SERIALIZABLE

序列化,事務(wù)最高隔離級別,它會強(qiáng)制事務(wù)排序,使之不會發(fā)生沖突,從而解決了臟讀、不可重復(fù)讀和幻讀問題,但因?yàn)閳?zhí)行效率低,所以真正使用的場景并不多。

簡單總結(jié)一下,MySQL 的 4 種事務(wù)隔離級別對應(yīng)臟讀、不可重復(fù)讀和幻讀的關(guān)系如下:

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

前置知識

1.事務(wù)相關(guān)的常用命令

  1. # 查看 MySQL 版本 
  2. select version(); 
  3.  
  4. # 開啟事務(wù) 
  5. start transaction
  6.  
  7. # 提交事務(wù) 
  8. commit
  9.  
  10. # 回滾事務(wù) 
  11. rollback

2.MySQL 8 之前查詢事務(wù)的隔離級別

查看全局 MySQL 事務(wù)隔離級別和當(dāng)前會話的事務(wù)隔離級別的 SQL 如下:

  1. select @@global.tx_isolation,@@tx_isolation; 

以上 SQL 執(zhí)行結(jié)果如下圖所示:

3.MySQL 8 之后查詢事務(wù)的隔離級別

  1. select @@global.transaction_isolation,@@transaction_isolation; 

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

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

  1. show processlist; 

以上 SQL 執(zhí)行結(jié)果如下:

5.查詢連接客戶端的數(shù)量

可以使用以下 SQL 命令,查詢連當(dāng)前接 MySQL 服務(wù)器的客戶端數(shù)量:

  1. show status like 'Threads%'

以上 SQL 執(zhí)行結(jié)果如下:

6.設(shè)置客戶端的事務(wù)隔離級別

通過以下 SQL 可以設(shè)置當(dāng)前客戶端的事務(wù)隔離級別:

  1. set session transaction isolation level 事務(wù)隔離級別; 

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

7.新建數(shù)據(jù)庫和測試數(shù)據(jù)

創(chuàng)建測試數(shù)據(jù)庫和表信息,執(zhí)行 SQL 如下:

  1. -- 創(chuàng)建數(shù)據(jù)庫 
  2. drop database if exists testdb; 
  3. create database testdb; 
  4. use testdb; 
  5. -- 創(chuàng)建表 
  6. create table userinfo( 
  7.   id int primary key auto_increment, 
  8.   name varchar(250) not null
  9.   balance decimal(10,2) not null default 0 
  10. ); 
  11. -- 插入測試數(shù)據(jù) 
  12. insert into userinfo(id,name,balance) values(1,'Java',100),(2,'MySQL',200); 

創(chuàng)建的表結(jié)構(gòu)和數(shù)據(jù)如下:

8.名稱約定

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

臟讀

一個事務(wù)讀到另外一個事務(wù)還沒有提交的數(shù)據(jù),稱之為臟讀。臟讀演示的執(zhí)行流程如下:

臟讀演示步驟1

設(shè)置窗口 2 的事務(wù)隔離級別為讀未提交,設(shè)置命令如下:

  1. set session transaction isolation level read uncommitted

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

然后使用命令來檢查當(dāng)前連接窗口的事務(wù)隔離界別,如下圖所示:

開啟事務(wù)并查詢用戶列表信息,如下圖所示:

臟讀演示步驟2

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

臟讀演示步驟3

在窗口 2 中再次查詢用戶列表,執(zhí)行結(jié)果如下:

從上述結(jié)果可以看出,在窗口 2 中讀取到了窗口 1 中事務(wù)未提交的數(shù)據(jù),這就是臟讀。

不可重復(fù)讀

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

 

 

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

不可重復(fù)讀演示步驟1

設(shè)置窗口 2 的事務(wù)隔離級別為讀已提交,設(shè)置命令如下:

  1. set session transaction isolation level read committed

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

使用命令來檢查當(dāng)前連接窗口的事務(wù)隔離界別,如下圖所示:

在窗口 2 中開啟事務(wù),并查詢用戶表,執(zhí)行結(jié)果如下:

此時查詢的列表中,Java 用戶的余額為 100 元。

不可重復(fù)讀演示步驟2

在窗口 1 中開啟事務(wù),并給 Java 用戶添加 20 元,但不提交事務(wù),再觀察窗口 2 中有沒有臟讀的問題,具體執(zhí)行結(jié)果如下圖所示:

從上述結(jié)果可以看出,當(dāng)把窗口的事務(wù)隔離級別設(shè)置為讀已提交,已經(jīng)不存在臟讀問題了。接下來在窗口 1 中提交事務(wù),執(zhí)行結(jié)果如下圖所示:

不可重復(fù)讀演示步驟3

切換到窗口 2 中再次查詢用戶列表,執(zhí)行結(jié)果如下:

從上述結(jié)果可以看出,此時 Java 用戶的余額已經(jīng)變成 120 元了。在同一個事務(wù)中,先后查詢的兩次結(jié)果不一致就是不可重復(fù)讀。

不可重復(fù)讀和臟讀的區(qū)別

臟讀可以讀到其他事務(wù)中未提交的數(shù)據(jù),而不可重復(fù)讀是讀取到了其他事務(wù)已經(jīng)提交的數(shù)據(jù),但前后兩次讀取的結(jié)果不同。

幻讀

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

具體執(zhí)行結(jié)果如下步驟所示。

幻讀演示步驟1

設(shè)置窗口 2 為可重復(fù)讀,可重復(fù)有幻讀的問題,查詢編號為 3 的用戶,具體執(zhí)行 SQL 如下:

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

以上 SQL 執(zhí)行結(jié)果如下圖所示:

從上述結(jié)果可以看出,查詢的結(jié)果中 id=3 的數(shù)據(jù)為空。

幻讀演示步驟2

開啟窗口 1 的事務(wù),插入用戶編號為 3 的數(shù)據(jù),然后成功提交事務(wù),執(zhí)行 SQL 如下:

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

以上 SQL 執(zhí)行結(jié)果如下圖所示:

幻讀演示步驟3

在窗口 2 中插入用戶編號為 3 的數(shù)據(jù),執(zhí)行 SQL 如下:

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

以上 SQL 執(zhí)行結(jié)果如下圖所示:

添加用戶數(shù)據(jù)失敗,提示表中已經(jīng)存在了編號為 3 的數(shù)據(jù),且此字段為主鍵,不能添加多個。

幻讀演示步驟4

在窗口 2 中,重新執(zhí)行查詢:

  1. select * from userinfo where id=3; 

以上 SQL 執(zhí)行結(jié)果如下圖所示:

在此事務(wù)中查詢明明沒有編號為 3 的用戶,但插入的時候卻卻提示已經(jīng)存在了,這就是幻讀。

 不可重復(fù)讀和幻讀的區(qū)別

二者描述的則重點(diǎn)不同,不可重復(fù)讀描述的側(cè)重點(diǎn)是修改操作,而幻讀描述的側(cè)重點(diǎn)是添加和刪除操作。

總結(jié)

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

 

責(zé)任編輯:姜華 來源: Java中文社群
相關(guān)推薦

2022-04-27 07:32:02

臟讀幻讀不可重復(fù)讀

2024-04-19 08:18:47

MySQLSQL隔離

2024-04-24 08:26:35

事務(wù)數(shù)據(jù)InnoDB

2019-03-21 09:06:00

數(shù)據(jù)庫復(fù)讀幻讀

2023-11-01 14:13:00

MySQL事務(wù)隔離級別

2025-02-26 10:40:44

數(shù)據(jù)庫并發(fā)幻讀

2018-01-03 09:02:13

不可重復(fù)讀幻讀MySQL

2022-06-29 11:01:05

MySQL事務(wù)隔離級別

2021-08-02 09:01:05

MySQL 多版本并發(fā)數(shù)據(jù)庫

2023-02-02 07:06:10

2021-04-20 19:21:50

臟讀MySQL幻讀

2023-10-26 00:41:46

臟讀數(shù)據(jù)幻讀

2024-05-13 11:46:33

MySQL數(shù)據(jù)庫

2019-05-28 13:50:27

MySQL幻讀數(shù)據(jù)庫

2024-07-16 08:19:46

MySQL數(shù)據(jù)InnoDB

2021-09-07 10:33:42

MySQL事務(wù)隔離性

2019-12-24 14:50:01

MySQL可重復(fù)讀數(shù)據(jù)庫

2023-08-09 17:22:30

MVCCMySQL數(shù)據(jù)

2023-12-26 08:08:02

Spring事務(wù)MySQL

2022-09-21 09:00:10

MySQL幻讀隔離級別
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號