MySQL 的 事務(wù)和隔離級別
事務(wù)是一組原子性的SQL查詢,事務(wù)內(nèi)的SQL語句,要么全部執(zhí)行成功,要么全部執(zhí)行失敗。本節(jié)重點介紹事務(wù)的ACID和隔離級別。
1. ACID
提到事務(wù),大家肯定都不陌生,和數(shù)據(jù)庫打交道,我們都會用到事務(wù)。銀行轉(zhuǎn)賬是解釋事務(wù)的一個經(jīng)典例子。銀行數(shù)據(jù)庫通常會有兩張表:支票表和儲蓄表。現(xiàn)在要從用戶 A 的支票賬戶轉(zhuǎn)賬 100 元人民幣到儲蓄賬戶,一般是下面三個步驟:
- 檢查支票賬戶的余額高于 100 元;
- 從支票賬戶余額減去 100 元;
- 在儲蓄賬戶余額增加 100 元;
相應(yīng)的 SQL 語句如下:
start transaction
select balance from checking where customer_name = 'A'
update checking set balance = balance - 100.00 where customer_name = 'A'
update savings set balance = balance + 100.00 where customer_name = 'A'
commit;
這三個步驟需要封裝成一個事務(wù),任何一個步驟失敗,都必須回滾所有的步驟。簡單的說,事務(wù)就是保證一組數(shù)據(jù)庫操作,要么全部執(zhí)行成功,要么全部執(zhí)行失敗。
一個優(yōu)秀的事務(wù)處理機制,需要具備 ACID 特性,即原子性(atomicity)、一致性(consistency)、隔離性(isolation)、持久性(durability)。
-
原子性(atomicity):一個事務(wù)被視為一個完整的最小工作單元,事務(wù)中的數(shù)據(jù)庫操作,要么全部執(zhí)行成功,要么全部執(zhí)行失敗回滾,不能只成功執(zhí)行了其中的一部分數(shù)據(jù)庫操作;
-
一致性(consistency):數(shù)據(jù)庫總是從一個一致性的狀態(tài)轉(zhuǎn)換到另一個一致性的狀態(tài)。在銀行轉(zhuǎn)賬的例子中,即使執(zhí)行到第四條 SQL 語句時失敗,用戶的支票賬戶也不會損失 100 元人民幣,因為執(zhí)行失敗時,事務(wù)進行了回滾,所做的修改并沒有保存到數(shù)據(jù)庫中;
-
隔離性(isolation):通常來說,一個事物所做的修改在提交以前,對其他事務(wù)是不可見的。在銀行轉(zhuǎn)賬的例子中,當(dāng)執(zhí)行完第三條 SQL 語句時,此時另外一個程序在匯總支票賬戶,它所查詢到的用戶A的支票賬戶,并沒有減去 100 元人民幣;
-
持久性(durability):事務(wù)提交成功,所做的修改就會永久保存到數(shù)據(jù)庫中,即使系統(tǒng)崩潰,修改的數(shù)據(jù)也不會丟失。
在 MySQL 中,事務(wù)是在存儲引擎層實現(xiàn)的。MySQL 是支持多種存儲引擎的數(shù)據(jù)庫,但并不是所有的存儲引擎都支持事務(wù),比如 MyISAM 就不支持事務(wù)。
事務(wù)增加了數(shù)據(jù)庫的安全性,同時也需要數(shù)據(jù)庫做很多額外的工作。相比沒有實現(xiàn) ACID 的數(shù)據(jù)庫,實現(xiàn)了 ACID 的數(shù)據(jù)庫需要更強的 CPU、內(nèi)存、以及磁盤空間。
2. 隔離級別
在 SQL 標(biāo)準(zhǔn)中,包含了四種隔離級別,即未提交讀(read uncommitted)、提交讀(read committed)、可重復(fù)讀(repeatable read)、可串行化(serializable)。
-
未提交讀(read uncommitted):一個事務(wù)還未提交,它所做的變更能被別的事務(wù)看到。事務(wù)可以讀取未提交的數(shù)據(jù),被稱為臟讀(dirty read),這種隔離級別在實際應(yīng)用中一般很少使用;
-
提交讀(read committed):一個事務(wù)提交之后,它所做的變更才能被別的事務(wù)看到。大多數(shù)數(shù)據(jù)庫的默認隔離級別是提交讀(read committed),比如 Oracle;
-
可重復(fù)讀(repeatable read):一個事務(wù)在執(zhí)行過程中看到的數(shù)據(jù),總是跟這個事務(wù)在啟動時看到的數(shù)據(jù)是一致的。在可重復(fù)讀隔離級別下,未提交變更對其他事務(wù)也是不可見的。該級別保證了在同一個事務(wù)中,多次讀取同樣記錄的結(jié)果是一致的。MySQL 的默認事務(wù)隔離級別是可重復(fù)讀(repeatable read);
-
可串行化(serializable):serializable 是最高的隔離級別。對同一行數(shù)據(jù),讀寫都會進行加鎖。當(dāng)出現(xiàn)鎖沖突時,后面訪問的事務(wù)必須等前一個事務(wù)完成,才能繼續(xù)執(zhí)行。實際應(yīng)用場景很少用到這種隔離級別,只有在非常需要確保數(shù)據(jù)一致性,而且可以接受沒有并發(fā)的情況,才會使用這種隔離級別。
下表為 ANSI SQL 隔離級別:
隔離級別 | 臟讀可能性 | 不可重復(fù)度可能性 | 幻讀可能性 | 加鎖讀 |
---|---|---|---|---|
未提交讀(read uncommitted) | yes | yes | yes | no |
提交讀(read committed) | no | yes | yes | no |
可重復(fù)讀(repeatable read) | no | no | yes | no |
可串行化(serializable) | no | no | no | yes |
3. 小結(jié)
本小節(jié)主要介紹了事務(wù)的 ACID 和隔離級別。
ACID特性:原子性(atomicity)、一致性(consistency)、隔離性(isolation)、持久性(durability)
隔離級別:未提交讀(read uncommitted)、提交讀(read committed)、可重復(fù)讀(repeatable read)、可串行化(serializable)