一文了解MySQL事務(wù)隔離級別
前言
MySQL 事務(wù)隔離級別是為了解決并發(fā)事務(wù)互相干擾的問題的,MySQL 事務(wù)隔離級別總共有以下 4 種:
- READ UNCOMMITTED:讀未提交。
- READ COMMITTED:讀已提交。
- REPEATABLE READ:可重復(fù)讀。
- SERIALIZABLE:序列化。
1.四種事務(wù)隔離級別
1.1 READ UNCOMMITTED
讀未提交,也叫未提交讀,該隔離級別的事務(wù)可以看到其他事務(wù)中未提交的數(shù)據(jù)。該隔離級別因為可以讀取到其他事務(wù)中未提交的數(shù)據(jù),而未提交的數(shù)據(jù)可能會發(fā)生回滾,因此我們把該級別讀取到的數(shù)據(jù)稱之為臟數(shù)據(jù),把這個問題稱之為臟讀。
1.2 READ COMMITTED
讀已提交,也叫提交讀,該隔離級別的事務(wù)能讀取到已經(jīng)提交事務(wù)的數(shù)據(jù),因此它不會有臟讀問題。但由于在事務(wù)的執(zhí)行中可以讀取到其他事務(wù)提交的結(jié)果,所以在不同時間的相同 SQL 查詢中,可能會得到不同的結(jié)果,這種現(xiàn)象叫做不可重復(fù)讀。
1.3 REPEATABLE READ
可重復(fù)讀,MySQL 默認(rèn)的事務(wù)隔離級別??芍貜?fù)讀可以解決“不可重復(fù)讀”的問題,但還存在幻讀的問題。所謂的幻讀指的是,在同一事務(wù)的不同時間使用相同 SQL 查詢時,會產(chǎn)生不同的結(jié)果。例如,一個 SELECT 被執(zhí)行了兩次,但是第二次返回了第一次沒有返回的一行,那么這一行就是一個“幻像”行。
注意:幻讀和不可重復(fù)讀的側(cè)重點是不同的,不可重復(fù)讀側(cè)重于數(shù)據(jù)修改,兩次讀取到的同一行數(shù)據(jù)不一樣;而幻讀側(cè)重于添加或刪除,兩次查詢返回的數(shù)據(jù)行數(shù)不同。
1.4 SERIALIZABLE
序列化,事務(wù)最高隔離級別,它會強制事務(wù)排序,使之不會發(fā)生沖突,從而解決了臟讀、不可重復(fù)讀和幻讀問題,但因為執(zhí)行效率低,所以真正使用的場景并不多。
1.5 小結(jié)
簡單總結(jié)一下,MySQL 中的事務(wù)隔離級別就是為了解決臟讀、不可重復(fù)讀和幻讀等問題的,這 4 種隔離級別與這 3 個問題之間的對應(yīng)關(guān)系如下:
事務(wù)隔離級別 | 臟讀 | 不可重復(fù)讀 | 幻讀 |
---|---|---|---|
讀未提交(READ UNCOMMITTED) | √ | √ | √ |
讀已提交(READ COMMITTED) | × | √ | √ |
可重復(fù)讀(REPEATABLE READ) | × | × | √ |
串行化(SERIALIZABLE) | × | × | × |
2.并發(fā)事務(wù)中的問題
并發(fā)事務(wù)中存在以下 3 個問題。
2.1 臟讀
一個事務(wù)讀取到了另一個事務(wù)為提交保存的數(shù)據(jù),之后此事務(wù)進行了回滾操作,從而導(dǎo)致第一個事務(wù)讀取了一個不存在的臟數(shù)據(jù)。
2.2 不可重復(fù)讀
在同一個事務(wù)中,同一個查詢在不同的時間得到了不同的結(jié)果。例如事務(wù)在 T1 讀取到了某一行數(shù)據(jù),在 T2 時間重新讀取這一行時候,這一行的數(shù)據(jù)已經(jīng)發(fā)生修改,所以再次讀取時得到了一個和 T1 查詢時不同的結(jié)果。
2.3 幻讀
MySQL 對幻讀的定義如下:
The so-called phantom problem occurs within a transaction when the same query produces different sets of rows at different times. For example, if a SELECT is executed twice, but returns a row the second time that was not returned the first time, the row is a “phantom” row.
官方文檔:翻譯為中文是:同一個查詢在不同時間得到了不同的結(jié)果,這就是事務(wù)中的幻讀問題。例如,一個 SELECT 被執(zhí)行了兩次,但是第二次返回了第一次沒有返回的一行,那么這一行就是一個“幻像”行。
3.隔離級別實戰(zhàn)
3.1 查詢事務(wù)隔離級別
查看全局 MySQL 事務(wù)隔離級別和當(dāng)前會話的事務(wù)隔離級別的 SQL 如下:
select @@global.tx_isolation,@@tx_isolation;
以上 SQL 執(zhí)行結(jié)果如下圖所示:
3.2 設(shè)置事務(wù)隔離級別
每個連接到 MySQL 的客戶端可以單獨設(shè)置事務(wù)的隔離級別,MySQL 可以使用以下 SQL 設(shè)置當(dāng)前連接(客戶端)的事務(wù)隔離級別:
set session transaction isolation level 事務(wù)隔離級別;
其中事務(wù)隔離級別有 4 個值:
- READ UNCOMMITTED
- READ COMMITTED
- REPEATABLE READ
- SERIALIZABLE
3.3 臟讀問題
一個事務(wù)讀取到了另一個事務(wù)為提交保存的數(shù)據(jù),之后此事務(wù)進行了回滾操作,從而導(dǎo)致第一個事務(wù)讀取了一個不存在的臟數(shù)據(jù)。接下來,我們使用 SQL 來演示一下臟讀問題。
正式開始之前,先創(chuàng)建一個測試表:
-- 創(chuàng)建一個城市表 drop table if exists city; create table city( id int primary key auto_increment, name varchar(250) not null );
臟讀的執(zhí)行順序如下:
臟讀的執(zhí)行 SQL 和執(zhí)行順序如下:
- 客戶端 A:set session transaction isolation level read uncommitted;
- 客戶端 A:start transaction;
- 客戶端 B:start transaction;
- 客戶端 B:insert into city(name) values('西安');
- 客戶端 A:select * from city;
- 客戶端 B:rollback;
- 客戶端 A:select * from city;
對應(yīng)的執(zhí)行結(jié)果如下圖所示:
從上述結(jié)果可以看出,當(dāng)把客戶端 A 設(shè)置為讀未提交的事務(wù)隔離級別后,客戶端 A 可以讀取到其他事務(wù)未提交的數(shù)據(jù),當(dāng)其他事務(wù)回滾之后,客戶端 A 讀取的數(shù)據(jù)就成了臟數(shù)據(jù),這就是臟讀,也就是讀未提交的事務(wù)隔離級別中存在臟讀的問題。
3.4 不可重復(fù)讀問題
在同一個事務(wù)中,同一個查詢在不同的時間得到了不同的結(jié)果。例如事務(wù)在 T1 讀取到了某一行數(shù)據(jù),在 T2 時間重新讀取這一行時候,這一行的數(shù)據(jù)已經(jīng)發(fā)生修改,所以再次讀取時得到了一個和 T1 查詢時不同的結(jié)果。
不可重復(fù)讀的執(zhí)行順序如下:
不可重復(fù)讀的執(zhí)行 SQL 和執(zhí)行順序如下:
- 客戶端 A:set session transaction isolation level read committed;
- 客戶端 A:start transaction;
- 客戶端 A:select * from city where id=1;
- 客戶端 B:start transaction;
- 客戶端 B:update city set name='長安' where id=1;
- 客戶端 B:commit;
- 客戶端 A:select * from city where id=1;
對應(yīng)執(zhí)行的結(jié)果如下圖所示:
從上述結(jié)果中可以看出,客戶端 A 被設(shè)置了讀已提交的事務(wù)隔離級別之后,使用同樣的 SQL 兩次讀取到的同一條數(shù)據(jù),內(nèi)容是不一樣的,這就是不可重復(fù)讀。也就是讀已提交的事務(wù)隔離級別中,可能存在不可重復(fù)讀的問題。
3.5 幻讀問題
同一個查詢在不同時間得到了不同的結(jié)果,這就是事務(wù)中的幻讀問題。例如,一個 SELECT 被執(zhí)行了兩次,但是第二次返回了第一次沒有返回的一行,那么這一行就是一個“幻像”行。
幻讀的執(zhí)行順序如下:
幻讀的執(zhí)行 SQL 和執(zhí)行順序如下: 客戶端 A:set session transaction isolation level repeatable read; 客戶端 A:start transaction; 客戶端 A:select * from city where id<5; --查詢出1條數(shù)據(jù) 客戶端 B:start transaction; 客戶端 B:insert into city(id,name) values(2,'北京'); 客戶端 B:commit; 客戶端 A:update city set name='京城' where id=2; 客戶端 A:select * from city where id<5; --查詢出2條數(shù)據(jù) 對應(yīng)執(zhí)行的結(jié)果如下圖所示:
從上述結(jié)果可以看出,客戶端 A 被設(shè)置了可重復(fù)讀的事務(wù)隔離級別之后,使用相同的 SQL 卻查詢出了一樣的結(jié)果,第一次查詢出了一條數(shù)據(jù),而第二次查詢出了兩條數(shù)據(jù),多出來的這行數(shù)據(jù)就叫做“幻像”行,因此我們可以得出結(jié)果,在可重復(fù)讀中可能會存在幻讀的問題。
總結(jié)
MySQL 中有 4 種事務(wù)隔離級別:讀未提交(存在臟讀/不可重復(fù)讀/幻讀問題)、讀已提交(存在不可重復(fù)讀/幻讀問題)、可重復(fù)讀(存在幻讀問題)和序列化,其中可重復(fù)讀是 MySQL 默認(rèn)的事務(wù)隔離級別。臟讀是讀到了其他事務(wù)未提交的數(shù)據(jù),不可重復(fù)讀是讀到了其他事務(wù)修改的數(shù)據(jù),而幻讀則是讀取到了其他事務(wù)新增或刪除的“幻像”行數(shù)據(jù)。
到此這篇關(guān)于一文了解MySQL事務(wù)隔離級別的文章就介紹到這了,更多相關(guān) MySQL事務(wù)隔離級別內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Mysql優(yōu)化技巧之Limit查詢的優(yōu)化分析
這篇文章主要給大家介紹了關(guān)于Mysql優(yōu)化技巧之Limit查詢的優(yōu)化分析,文中通過示例代碼介紹的非常詳細(xì),對大家學(xué)習(xí)或者使用Mysql具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧2019-07-07Ubuntu下啟動、停止、重啟MySQL,查看錯誤日志命令大全
這篇文章主要介紹了Ubuntu下啟動、停止、重啟MySQL,查看錯誤日志命令大全,需要的朋友可以參考下2014-06-06mysql 獲取規(guī)定時間段內(nèi)的統(tǒng)計數(shù)據(jù)
這篇文章主要介紹了mysql 獲取規(guī)定時間段內(nèi)的統(tǒng)計數(shù)據(jù)的相關(guān)資料,需要的朋友可以參考下2017-05-05Linux7.6二進制安裝Mysql8.0.27詳細(xì)操作步驟
大家好,本篇文章主要講的是Linux7.6二進制安裝Mysql8.0.27詳細(xì)操作步驟,感興趣的同學(xué)快來看一看吧,希望對你起到幫助2021-11-11Mysql 導(dǎo)入導(dǎo)出csv 中文亂碼問題的解決方法
這篇文章介紹了Mysql 導(dǎo)入導(dǎo)出csv 中文亂碼問題的解決方法,有需要的朋友可以參考一下2013-09-09MySQL普通表轉(zhuǎn)換為分區(qū)表實戰(zhàn)指南
本文將詳細(xì)指導(dǎo)新手開發(fā)者如何將MySQL中的普通表轉(zhuǎn)換為分區(qū)表,分區(qū)表在處理龐大數(shù)據(jù)集時展現(xiàn)出顯著的性能優(yōu)勢,不僅能大幅提升查詢速度,還能有效簡化數(shù)據(jù)維護工作,文中有詳細(xì)的代碼示例供大家參考,需要的朋友可以參考下2024-06-06