MySQL中的事務(wù)隔離級別詳解
一、事務(wù)并發(fā)問題
在多個事務(wù)同時操作同一份數(shù)據(jù)時,可能會出現(xiàn)以下幾種并發(fā)問題:
- 臟讀(Dirty Read):一個事務(wù)讀取了另一個未提交事務(wù)修改的數(shù)據(jù),如果后者回滾,則前者讀取到的數(shù)據(jù)是無效的。
- 不可重復(fù)讀(Non-repeatable Read):同一個事務(wù)中,執(zhí)行兩次相同的查詢,由于另一個事務(wù)的提交,查詢結(jié)果不同。
- 幻讀(Phantom Read):一個事務(wù)在兩次查詢之間,另一事務(wù)插入或刪除了數(shù)據(jù),導(dǎo)致前后查詢的記錄數(shù)不一致。
為了避免這些問題,SQL 標(biāo)準(zhǔn)定義了四種事務(wù)隔離級別,MySQL 也支持這四種級別。
二、MySQL 事務(wù)隔離級別
MySQL 通過 SET TRANSACTION ISOLATION LEVEL
語句來設(shè)置事務(wù)隔離級別:
SET SESSION TRANSACTION ISOLATION LEVEL <級別>; SET GLOBAL TRANSACTION ISOLATION LEVEL <級別>;
其中 <級別>
可以是 READ UNCOMMITTED
、READ COMMITTED
、REPEATABLE READ
或 SERIALIZABLE
。
1. READ UNCOMMITTED(讀未提交)
特點(diǎn):
- 事務(wù)可以讀取其他未提交事務(wù)的數(shù)據(jù)。
- 可能發(fā)生“臟讀”問題。
- 性能較好,因?yàn)椴粫褂面i限制讀取。
示例:
- 事務(wù)A修改了一條記錄但尚未提交。
- 事務(wù)B在事務(wù)A提交之前讀取了修改后的數(shù)據(jù)。
- 如果事務(wù)A回滾,那么事務(wù)B讀取到的數(shù)據(jù)就是“臟數(shù)據(jù)”。
適用場景:
- 允許讀取未提交的數(shù)據(jù),適用于不太關(guān)心數(shù)據(jù)一致性的應(yīng)用,如日志記錄、監(jiān)控數(shù)據(jù)等。
2. READ COMMITTED(讀已提交)
特點(diǎn):
- 只能讀取已經(jīng)提交的數(shù)據(jù),避免了“臟讀”。
- 可能發(fā)生“不可重復(fù)讀”問題。
- MySQL InnoDB 通過 MVCC(多版本并發(fā)控制)來實(shí)現(xiàn)此隔離級別。
示例:
- 事務(wù)A讀取一條記錄。
- 事務(wù)B修改該記錄并提交。
- 事務(wù)A再次讀取該記錄,發(fā)現(xiàn)數(shù)據(jù)發(fā)生了變化(不可重復(fù)讀)。
適用場景:
- 適用于大多數(shù) OLTP(在線事務(wù)處理)系統(tǒng),如銀行轉(zhuǎn)賬、訂單管理系統(tǒng),保證讀取的數(shù)據(jù)是已提交的但允許數(shù)據(jù)更新。
3. REPEATABLE READ(可重復(fù)讀)(MySQL 默認(rèn)級別)
特點(diǎn):
- 事務(wù)內(nèi)多次讀取同一條數(shù)據(jù)時,數(shù)據(jù)保持一致(即使其他事務(wù)修改并提交了數(shù)據(jù))。
- 通過 MVCC 實(shí)現(xiàn)可重復(fù)讀。
- 避免了“臟讀”和“不可重復(fù)讀”。
- 但仍然可能發(fā)生“幻讀”問題。
示例:
- 事務(wù)A第一次讀取某條數(shù)據(jù)。
- 事務(wù)B修改該數(shù)據(jù)并提交。
- 事務(wù)A再次讀取該數(shù)據(jù),發(fā)現(xiàn)數(shù)據(jù)未改變(因?yàn)槭聞?wù)A讀取的是事務(wù)開始時的快照)。
如何解決幻讀?
- MySQL InnoDB 通過 間隙鎖(Next-Key Locking) 機(jī)制來解決幻讀問題,即鎖住范圍,使得其他事務(wù)無法插入新的數(shù)據(jù),從而防止幻讀。
適用場景:
- 適用于高并發(fā)場景,尤其是金融行業(yè),如銀行賬戶查詢和訂單管理系統(tǒng)。
4. SERIALIZABLE(可串行化)
特點(diǎn):
- 最高級別的隔離,完全避免臟讀、不可重復(fù)讀和幻讀。
- 事務(wù)必須依次執(zhí)行,不能并行,通常會使用 表鎖 或 行鎖。
- 并發(fā)性能極差,適用于對數(shù)據(jù)一致性要求極高的場景。
示例:
- 事務(wù)A讀取某一條數(shù)據(jù),同時事務(wù)B必須等事務(wù)A完成后才能讀取或修改該數(shù)據(jù)。
適用場景:
- 適用于需要嚴(yán)格數(shù)據(jù)一致性的場景,如財務(wù)結(jié)算、票務(wù)系統(tǒng)等。
三、MySQL 默認(rèn)事務(wù)隔離級別
MySQL InnoDB 存儲引擎的默認(rèn)事務(wù)隔離級別是 REPEATABLE READ(可重復(fù)讀),這與 SQL 標(biāo)準(zhǔn)的默認(rèn)級別(READ COMMITTED)不同。MySQL 通過 MVCC(多版本并發(fā)控制)和 間隙鎖 解決了幻讀問題,因此 REPEATABLE READ 在 MySQL 中比 SQL 標(biāo)準(zhǔn)更強(qiáng)。
如果想修改默認(rèn)的事務(wù)隔離級別,可以在 my.cnf
(MySQL 配置文件)中修改:
[mysqld] transaction-isolation = REPEATABLE-READ
或在運(yùn)行時更改:
SET GLOBAL TRANSACTION ISOLATION LEVEL READ COMMITTED;
四、不同隔離級別對并發(fā)問題的影響
隔離級別 | 臟讀(Dirty Read) | 不可重復(fù)讀(Non-repeatable Read) | 幻讀(Phantom Read) |
---|---|---|---|
READ UNCOMMITTED | 可能發(fā)生 ? | 可能發(fā)生 ? | 可能發(fā)生 ? |
READ COMMITTED | 不會發(fā)生 ? | 可能發(fā)生 ? | 可能發(fā)生 ? |
REPEATABLE READ | 不會發(fā)生 ? | 不會發(fā)生 ? | 可能發(fā)生 ?(MySQL 中不會) |
SERIALIZABLE | 不會發(fā)生 ? | 不會發(fā)生 ? | 不會發(fā)生 ? |
五、如何選擇合適的隔離級別?
- READ UNCOMMITTED:適用于對數(shù)據(jù)一致性要求不高的場景,如日志分析、緩存數(shù)據(jù)等。
- READ COMMITTED:適用于大多數(shù)業(yè)務(wù)場景,如電商系統(tǒng)、用戶管理系統(tǒng)等,避免臟讀,提高并發(fā)性能。
- REPEATABLE READ(MySQL 默認(rèn)):適用于金融系統(tǒng)、庫存管理,保證事務(wù)內(nèi)數(shù)據(jù)的一致性,防止不可重復(fù)讀。
- SERIALIZABLE:適用于對數(shù)據(jù)一致性要求極高的場景,如銀行結(jié)算、核心財務(wù)系統(tǒng),但性能損耗較大。
總結(jié)
- READ UNCOMMITTED:可能發(fā)生臟讀、不可重復(fù)讀、幻讀,性能最高但安全性最低。
- READ COMMITTED:防止臟讀,但可能發(fā)生不可重復(fù)讀和幻讀。
- REPEATABLE READ(MySQL 默認(rèn)):防止臟讀和不可重復(fù)讀,MySQL 還能避免幻讀,適用于大多數(shù)高并發(fā)業(yè)務(wù)。
- SERIALIZABLE:所有并發(fā)問題都能避免,但性能最差。
MySQL 默認(rèn)采用 REPEATABLE READ,主要是因?yàn)?MySQL 通過 MVCC 解決了大部分的并發(fā)問題,既能保持較高的事務(wù)隔離級別,又不會影響太多的性能。
MySQL中的事務(wù)隔離級別有四種,分別為:
讀未提交(Read Uncommitted):
該級別允許事務(wù)讀取其他事務(wù)尚未提交的數(shù)據(jù)(臟讀)。這意味著一個事務(wù)可以讀取到另一個事務(wù)中間狀態(tài)的數(shù)據(jù),可能會導(dǎo)致數(shù)據(jù)不一致。讀已提交(Read Committed):
該級別保證事務(wù)只能讀取到已提交的數(shù)據(jù),防止臟讀。即使如此,仍然允許發(fā)生“不可重復(fù)讀”(在同一事務(wù)中兩次讀取同一數(shù)據(jù),值可能不同,因?yàn)榱硪粋€事務(wù)已經(jīng)修改了數(shù)據(jù)并提交)。可重復(fù)讀(Repeatable Read):
該級別保證在一個事務(wù)中多次讀取同一數(shù)據(jù)時,結(jié)果始終一致,避免了“不可重復(fù)讀”。但是,仍然可能會出現(xiàn)“幻讀”(即事務(wù)讀取的結(jié)果集發(fā)生了變化,因?yàn)榱硪粋€事務(wù)插入了新的記錄)。串行化(Serializable):
這是最高的隔離級別,強(qiáng)制事務(wù)串行執(zhí)行,即事務(wù)排隊(duì)執(zhí)行,一個事務(wù)在完成之前,其他事務(wù)無法訪問相同的數(shù)據(jù)。這可以完全避免臟讀、不可重復(fù)讀和幻讀,但性能會較低。
到此這篇關(guān)于MySQL中的事務(wù)隔離級別有哪些的文章就介紹到這了,更多相關(guān)mysql事務(wù)隔離級別內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- 生產(chǎn)環(huán)境的MySQL事務(wù)隔離級別方式
- MySQL的事務(wù)的基本要素和事務(wù)隔離級別詳解
- mysql的事務(wù)隔離級別詳細(xì)解析
- 一文帶你搞懂MySQL的事務(wù)隔離級別
- 一文帶你了解MySQL之事務(wù)隔離級別和MVCC
- 解決MySql8.0 查看事務(wù)隔離級別報錯的問題
- 詳解MySQL中事務(wù)隔離級別的實(shí)現(xiàn)原理
- mysql、oracle默認(rèn)事務(wù)隔離級別的說明
- MySQL事務(wù)及Spring隔離級別實(shí)現(xiàn)原理詳解
- MySQL查看和修改事務(wù)隔離級別的實(shí)例講解
- MySQL四種事務(wù)隔離級別詳解
相關(guān)文章
MySQL 不用存儲過程循環(huán)插入數(shù)據(jù)的方法
在MySQL中,使用INSERT INTO VALUES語句可以一次性插入多行數(shù)據(jù),提高插入效率,還可通過Python的pymysql庫生成和執(zhí)行插入語句,這不僅減少了操作時間,還提高了代碼的簡潔性和執(zhí)行效率2024-09-09mysql5.x升級到mysql5.7后導(dǎo)入之前數(shù)據(jù)庫date出錯的快速解決方法
這篇文章主要介紹了mysql5.x升級到mysql5.7后導(dǎo)入之前數(shù)據(jù)庫date出錯的快速解決方法,非常不錯,具有參考借鑒價值,需要的朋友可以參考下2016-09-09php連接不上mysql但mysql命令行操作正常的解決方法
這篇文章主要介紹了php連接不上mysql但mysql命令行操作正常的解決方法,需要的朋友可以參考下2014-04-04