深入理解MySQL事務(wù)的4種隔離級(jí)別
1 簡(jiǎn)介
事務(wù)的4種隔離級(jí)別分別是讀未提交(Read Uncommitted)、讀已提交(Read Committed)、 可重復(fù)讀(Repeatable Read)和串行化(Serializable)。
首先,在了解這4種隔離級(jí)別前就必須先要了解其前提,也就是事務(wù),本文簡(jiǎn)單介紹一下關(guān)于事務(wù)。
之后,我們也要理解這4種隔離級(jí)別產(chǎn)生的原因和場(chǎng)景展現(xiàn)以及4種隔離級(jí)別是如何解決問(wèn)題的。
2 什么是數(shù)據(jù)庫(kù)事務(wù)?
事務(wù)由一個(gè)有限的數(shù)據(jù)庫(kù)操作序列組成,這些操作要么全部執(zhí)行,要么全部不執(zhí)行,是一個(gè)不可分割的工作單位。
例如一個(gè)銀行轉(zhuǎn)賬場(chǎng)景:
A轉(zhuǎn)賬B 100元,A的賬號(hào)扣除100元,B的賬號(hào)加上100塊。假如中間出現(xiàn)任何異常,例如,在A的賬號(hào)扣100元時(shí),銀行癱瘓,B的賬號(hào)余額沒(méi)有發(fā)生變化。這時(shí)候就需要事務(wù)來(lái)保證將A的錢(qián)還回去。
2.1 事務(wù)的四大特性(ACID)
- 原子性:事務(wù)作為一個(gè)整體被執(zhí)行,包含在其中的對(duì)數(shù)據(jù)庫(kù)的操作要么全部都執(zhí)行,要么都不執(zhí)行。
- 一致性:指在事務(wù)開(kāi)始之前和事務(wù)結(jié)束以后,數(shù)據(jù)不會(huì)被破壞,假如A賬戶給B賬戶轉(zhuǎn)10塊錢(qián),不管成功與否,A和B的總金額是不變的。
- 隔離性:多個(gè)事務(wù)并發(fā)訪問(wèn)時(shí),事務(wù)之間是相互隔離的,一個(gè)事務(wù)不應(yīng)該被其他事務(wù)干擾,多個(gè)并發(fā)事務(wù)之間要相互隔離。
- 持久性:表示事務(wù)完成提交后,該事務(wù)對(duì)數(shù)據(jù)庫(kù)所作的操作更改,將持久地保存在數(shù)據(jù)庫(kù)之中。
3 并發(fā)事務(wù)會(huì)導(dǎo)致的問(wèn)題
- 臟讀:事務(wù) A 讀取了事務(wù) B 更新的數(shù)據(jù),然后 B 進(jìn)行回滾操作,那么A讀取的數(shù)據(jù)就是臟數(shù)據(jù)
- 不可重復(fù)讀:事務(wù)A多次讀取同一數(shù)據(jù),事務(wù)B在事務(wù)A多次讀取的過(guò)程中,對(duì)數(shù)據(jù)做了更新并提交,導(dǎo)致事務(wù)A多次奪取同一數(shù)據(jù)時(shí),結(jié)果不一致。
- 幻讀:系統(tǒng)管理員A將數(shù)據(jù)庫(kù)中所有學(xué)生的成績(jī)從具體分?jǐn)?shù)改為ABCDE等級(jí),但是系統(tǒng)管理員B就在這個(gè)時(shí)候插入了一條具體分?jǐn)?shù)的記錄,當(dāng)系統(tǒng)管理員A改結(jié)束后發(fā)現(xiàn)還有一條記錄沒(méi)有改過(guò)來(lái),就好像發(fā)生了幻覺(jué)一樣,這就叫幻讀。
?? 不可重復(fù)讀的和幻讀很容易混淆,不可重復(fù)讀側(cè)重于修改,幻讀側(cè)重于新增或刪除。解決不可重復(fù)讀的問(wèn)題只需鎖住滿足條件的行,解決幻讀需要鎖表。
3.1 本文會(huì)使用到的 SQL 語(yǔ)句
3.1.1 示例表結(jié)構(gòu)
CREATE TABLE `account` ( `id` int(11) NOT NULL, `name` varchar(255) DEFAULT NULL, `balance` int(11) DEFAULT NULL, PRIMARY KEY (`id`), UNIQUE KEY `un_name_idx` (`name`) USING BTREE ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
3.1.2 查詢事務(wù)的默認(rèn)隔離級(jí)別
mysql> select @@transaction_isolation; +-------------------------+ | @@transaction_isolation | +-------------------------+ | REPEATABLE-READ | +-------------------------+ 1 row in set (0.01 sec)
3.1.3 設(shè)置當(dāng)前會(huì)話的事務(wù)隔離級(jí)別
mysql> set session transaction isolation level read uncommitted; Query OK, 0 rows affected (0.00 sec)
4 事務(wù)的4種隔離級(jí)別和示例演示
事務(wù)隔離級(jí)別 | 臟讀 | 不可重復(fù)讀 | 幻讀 |
---|---|---|---|
讀未提交(read-uncommitted) | 是 | 是 | 是 |
不可重復(fù)讀(read-committed)又叫讀已提交 | 否 | 是 | 是 |
可重復(fù)讀(repeatable-read) | 否 | 否 | 是 |
串行化(serializable) | 否 | 否 | 否 |
4.1 讀未提交
事務(wù)A:
事務(wù)B:
?? 讀未提交是隔離級(jí)別最低的,會(huì)造成臟讀。
4.2 讀已提交
為了避免臟讀,數(shù)據(jù)庫(kù)有了比讀未提交更高的隔離級(jí)別,即讀已提交。
對(duì)于提交:當(dāng)前事務(wù)只能讀取其它事務(wù)已提交的數(shù)據(jù),未提交事務(wù)的數(shù)據(jù)讀取不到。
事務(wù)A:
事務(wù)B:
由此可以得出結(jié)論,隔離級(jí)別設(shè)置為已提交讀(READ COMMITTED)
時(shí),已經(jīng)不會(huì)出現(xiàn)臟讀問(wèn)題了,當(dāng)前事務(wù)只能讀取到其他事務(wù)提交的數(shù)據(jù)。但是,站在事務(wù)A的角度想想,存在其他問(wèn)題嗎?
提交讀的隔離級(jí)別會(huì)有什么問(wèn)題呢?
在同一個(gè)事務(wù)A里,相同的查詢sql,讀取同一條記錄(id=1),讀到的結(jié)果是不一樣的,即不可重復(fù)讀。所以,隔離級(jí)別設(shè)置為read committed
的時(shí)候,還會(huì)存在不可重復(fù)讀的并發(fā)問(wèn)題。
4.3 可重復(fù)讀
為了避免不可重復(fù)讀的并發(fā)問(wèn)題,我們將隔離級(jí)別設(shè)置為可重復(fù)讀(REPEATABLEE READ),重復(fù)一下之前的操作。
事務(wù)A:
事務(wù)B:
到了這一步,可以發(fā)現(xiàn)事務(wù)隔離級(jí)別設(shè)置為可重復(fù)讀,可以解決幻讀問(wèn)題。
那么可重復(fù)讀真的是否已經(jīng)解決了幻讀問(wèn)題呢?畢竟還剩個(gè)事務(wù)隔離級(jí)別呢。
RR隔離級(jí)別下,手動(dòng)啟動(dòng)一個(gè)事務(wù),進(jìn)行select操作,他會(huì)生成一個(gè)快照,可以理解為將當(dāng)前數(shù)據(jù)庫(kù)的數(shù)據(jù)復(fù)制一份,在當(dāng)前事務(wù)中,之后不管進(jìn)行多少次select查詢,都是在模板中去取數(shù)據(jù),所以不管數(shù)據(jù)庫(kù)中是否對(duì)數(shù)據(jù)進(jìn)行了改變,都不會(huì)影響當(dāng)前事務(wù)數(shù)據(jù)的讀取,從而避免了幻讀。這種普通的 select 操作,稱為快照讀。
但是如果在當(dāng)前事務(wù)中使用了下圖語(yǔ)句進(jìn)行當(dāng)前讀:
select * from account for update;
for update
是進(jìn)行當(dāng)前讀的操作,他會(huì)重新從數(shù)據(jù)庫(kù)去加載當(dāng)前的最新的數(shù)據(jù),每執(zhí)行一次加載一次,如果在此時(shí),另外一個(gè)事務(wù)為數(shù)據(jù)庫(kù)添加了一個(gè)事務(wù),再進(jìn)行查詢,會(huì)發(fā)現(xiàn)查詢的數(shù)據(jù)與之前相比多了或者少了,這也就是幻讀現(xiàn)象。
如果你閱讀到這里,去實(shí)操一下,會(huì)發(fā)現(xiàn)和我說(shuō)的不一樣,有一種上當(dāng)?shù)母杏X(jué)。
其實(shí)不是的,這是因?yàn)樯鲜龆际窃跇?biāo)準(zhǔn)的可重復(fù)讀下的情況,在innodb存儲(chǔ)引擎中對(duì)可重復(fù)讀進(jìn)行了改造,為當(dāng)前讀加上了 Next-key Lock
,也就是間隙鎖和行鎖的統(tǒng)稱,行鎖防止了別的事務(wù)修改或者刪除,間隙鎖防止了別的事務(wù)新增。也就是在進(jìn)行上面的for update
事務(wù)中,其他的事務(wù)不能對(duì)數(shù)據(jù)進(jìn)行增刪操作,執(zhí)行會(huì)報(bào)錯(cuò)或者長(zhǎng)時(shí)間處于等待狀態(tài)。
?? 注意:如果A事務(wù)如果進(jìn)行了快照讀,然后通過(guò)B事務(wù)對(duì)數(shù)據(jù)就行增刪,然后緊接著A事務(wù)進(jìn)行當(dāng)前讀操作,兩次讀取數(shù)據(jù)不一致,不能算作幻讀,因?yàn)榛米x定義是同一個(gè)select語(yǔ)句,快照讀和當(dāng)前讀的查詢語(yǔ)句是不一樣的.
小結(jié)
- 數(shù)據(jù)庫(kù)的并發(fā)問(wèn)題有:臟讀、不可重復(fù)讀和幻讀;
- 事務(wù)隔離級(jí)別依次為:讀未提交、讀已提交、可重復(fù)讀和串行化;
- 在標(biāo)準(zhǔn)的RR下并沒(méi)有徹底解決幻讀,但是在Mysql的innodb引擎中徹底解決了;
- innodb通過(guò) Next-Key lock解決的幻讀問(wèn)題,其實(shí)也就是阻塞串行化了;
- 不能把快照讀和當(dāng)前讀在一個(gè)事務(wù)中進(jìn)行比較是否出現(xiàn)幻讀,兩者不是同一個(gè)select,不滿足幻讀的官方定義。
4.4 串行化
略,這部分我懶得放圖了,因?yàn)榻Y(jié)果和上面沒(méi)啥差別。
文獻(xiàn)引用
一文徹底讀懂MySQL事務(wù)的四大隔離級(jí)別 - Jay_huaxiao - 博客園
到此這篇關(guān)于深入理解MySQL事務(wù)的4種隔離級(jí)別的文章就介紹到這了,更多相關(guān)MySQL事務(wù)隔離內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Navicat for MySQL(mysql圖形化管理工具)是什么?
這里就給大家介紹一個(gè)常用的MySQL數(shù)據(jù)庫(kù)管理工具:Navicat for MySQL,需要的朋友可以參考下2015-09-09MYSQL數(shù)字函數(shù)詳解及實(shí)戰(zhàn)記錄(數(shù)字函數(shù)大全,內(nèi)含示例)
數(shù)學(xué)運(yùn)算函數(shù)可以實(shí)現(xiàn)常見(jiàn)的數(shù)學(xué)運(yùn)算,這篇文章主要給大家介紹了關(guān)于MYSQL數(shù)字函數(shù)詳解及實(shí)戰(zhàn)的相關(guān)資料,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下2024-01-01MySQL關(guān)于ERROR 1290 (HY000)報(bào)錯(cuò)解決方法
在本篇文章里小編給大家整理的是關(guān)于MySQL關(guān)于ERROR 1290 (HY000)報(bào)錯(cuò)的解決方法,有興趣的朋友們可以參考下。2019-09-09The MySQL server is running with the --read-only option so i
1209 - The MySQL server is running with the --read-only option so it cannot execute this statement2020-08-08Windows 8下MySQL Community Server 5.6安裝配置方法圖文教程
這篇文章主要為大家詳細(xì)介紹了Windows 8下MySQL Community Server 5.6安裝配置方法圖文教程,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-09-09mysql優(yōu)化小技巧之去除重復(fù)項(xiàng)實(shí)現(xiàn)方法分析【百萬(wàn)級(jí)數(shù)據(jù)】
這篇文章主要介紹了mysql優(yōu)化小技巧之去除重復(fù)項(xiàng)實(shí)現(xiàn)方法,結(jié)合實(shí)例形式分析了mysql去除重復(fù)項(xiàng)的方法,并附帶了隨機(jī)查詢優(yōu)化的相關(guān)操作技巧,需要的朋友可以參考下2020-01-01很全面的MySQL處理重復(fù)數(shù)據(jù)代碼
這篇文章主要為大家詳細(xì)介紹了MySQL處理重復(fù)數(shù)據(jù)的實(shí)現(xiàn)代碼,如何防止數(shù)據(jù)表出現(xiàn)重復(fù)數(shù)據(jù)及如何刪除數(shù)據(jù)表中的重復(fù)數(shù)據(jù),感興趣的小伙伴們可以參考一下2016-05-05