MySQL 学习笔记(9)— 事务控制语句、事务属性以及并发和隔离级别
1. 事務(wù)概念
事務(wù)處理(transaction processing)可以用來維護(hù)數(shù)據(jù)庫的完整性,它保證成批的 MySQL 操作要么完全執(zhí)行,要么完全不執(zhí)行。
下面是關(guān)于事務(wù)處理需要知道的幾個術(shù)語:
- 事務(wù)(
transaction)指一組SQL語句; - 回退(
rollback)指撤銷指定SQL語句的過程; - 提交(
commit)指將未存儲的SQL語句結(jié)果寫入數(shù)據(jù)庫表; - 保留點(diǎn)(
savepoint)指事務(wù)處理中設(shè)置的臨時占位符(placeholder),
你可以對它發(fā)布回退(與回退整個事務(wù)處理不同)。
事務(wù)僅僅適應(yīng)于 INSERT、UPDATE、DELETE,對 SELECT、CREATE、DROP不生效。
2. 事務(wù)控制語句
SQL 定義了用于管理數(shù)據(jù)庫事務(wù)的事務(wù)控制語句(Transaction Control Language)。MySQL 實(shí)現(xiàn)了以下語句:
BEGIN或者START TRANSACTION,開始一個事務(wù);COMMIT,提交事務(wù);ROLLBACK,撤銷事務(wù);SAVEPOINT,事務(wù)保存點(diǎn),用于撤銷部分事務(wù);SET autocommit = {0 | 1},設(shè)置事務(wù)是否自動提交。
實(shí)際上,由于 MySQL 默認(rèn)啟用了自動提交(autocommit),任何數(shù)據(jù)操作都會自動提交:
show variables like 'autocommit';
Variable_name|Value|
-------------|-----|
autocommit |ON |INSERT INTO bank_card VALUES ('62220803', 'C', 2000);
接下來我們看一下 ROLLBACK 命令的作用:
BEGIN;
INSERT INTO bank_card VALUES ('62220804', 'D', 1000);
ROLLBACK;
其中,BEGIN 開始一個新的事務(wù);然后插入一條記錄;最后使用 ROLLBACK 撤銷該事務(wù)。因此,最終不會創(chuàng)建卡號為 “62220804” 的記錄。
Oracle支持事務(wù)管理的COMMIT、ROLLBACK以及SAVEPOINT語句。Oracle中不需要手動開始事務(wù),一個事務(wù)的結(jié)束意味著另一個事務(wù)的開始。
SQL Server支持事務(wù)管理的BEGIN TRANSACTION、COMMIT、ROLLBACK以及SAVE TRANSACTION語句。
PostgreSQL支持事務(wù)管理的BEGIN、COMMIT、ROLLBACK以及SAVEPOINT語句。
3. 事務(wù)的 ACID 屬性
SQL 標(biāo)準(zhǔn)定義了數(shù)據(jù)庫事務(wù)的四種特性:ACID。
3.1 原子性
原子性(Atomic)是指一個事務(wù)包含的所有 SQL 語句要么全部成功,要么全部失敗。
例如,某個事務(wù)需要更新 100 條記錄;但是在更新到一半時系統(tǒng)出現(xiàn)故障,數(shù)據(jù)庫必須保證能夠回滾已經(jīng)修改過的數(shù)據(jù),就像沒有執(zhí)行過任何修改一樣。
3.2 一致性
一致性(Consistency)意味著事務(wù)開始之前,數(shù)據(jù)庫位于一致性的狀態(tài);事務(wù)完成之后,數(shù)據(jù)庫仍然位于一致性的狀態(tài)。
例如,銀行轉(zhuǎn)賬事務(wù)中;如果一個賬戶扣款成功,但是另一個賬戶加錢失敗,就會出現(xiàn)數(shù)據(jù)不一致(此時需要回滾已經(jīng)執(zhí)行的扣款操作)。另外,數(shù)據(jù)庫還必須保證滿足完整性約束,比如賬戶扣款之后不能出現(xiàn)余額為負(fù)數(shù)(在余額字段上添加檢查約束)。
3.3 隔離性
隔離性(Isolation)與并發(fā)事務(wù)有關(guān),一個事務(wù)的影響在提交之前對其他事務(wù)不可見,多個并發(fā)的事務(wù)之間相互隔離。
例如,賬戶 A 向賬戶 B 轉(zhuǎn)賬的過程中,賬戶 B 查詢的余額應(yīng)該是轉(zhuǎn)賬之前的數(shù)目;如果多人同時向賬戶 B 轉(zhuǎn)賬,結(jié)果也應(yīng)該保持一致性,和依次進(jìn)行轉(zhuǎn)賬的結(jié)果一樣。SQL 標(biāo)準(zhǔn)定義了 4 種不同的事務(wù)隔離級別,我們將會在下文進(jìn)行介紹。
3.3 持久性
持久性(Durability)表示已經(jīng)提交的事務(wù)必須永久生效,即使發(fā)生斷電、系統(tǒng)崩潰等故障,數(shù)據(jù)庫都不會丟失數(shù)據(jù)。
數(shù)據(jù)庫系統(tǒng)通常使用重做日志(REDO)或者預(yù)寫式日志(WAL)實(shí)現(xiàn)事務(wù)的持久性。簡單來說,它們都是在提交之前將數(shù)據(jù)的修改操作記錄到日志文件中;當(dāng)數(shù)據(jù)庫出現(xiàn)崩潰時,可以利用這些日志重做之前的修改,從而避免數(shù)據(jù)的丟失。
對于我們開發(fā)者而言,重點(diǎn)需要注意的是隔離級別,而隔離級別又與并發(fā)訪問有關(guān)。
4. 并發(fā)和隔離級別
數(shù)據(jù)庫的并發(fā)意味著多個用戶同時訪問相同的數(shù)據(jù),例如 A 和 C 同時給 B 轉(zhuǎn)賬。數(shù)據(jù)庫的并發(fā)訪問可能帶來以下問題:
4.1 臟讀(Dirty Read)
當(dāng)一個事務(wù)允許讀取另一個事務(wù)修改但未提交的數(shù)據(jù)時,就可能發(fā)生臟讀。
例如,B 的初始余額為 0;A 向 B 轉(zhuǎn)賬 1000 元但沒有提交;此時 B 能夠看到 A 轉(zhuǎn)過來的 1000 元,并且成功取款 1000 元;然后 A 取消了轉(zhuǎn)賬;銀行損失了 1000 元。很顯然,銀行不會允許這種事情發(fā)生。
4.2 不可重復(fù)讀(Nonrepeatable Read)
一個事務(wù)讀取某一記錄后,該數(shù)據(jù)被另一個事務(wù)修改提交,再次讀取該記錄時結(jié)果發(fā)生了改變。
例如,B 查詢初始余額為 0;此時 A 向 B 轉(zhuǎn)賬 1000 元并且提交;B 再次查詢發(fā)現(xiàn)余額變成了 1000 元,以為天上掉餡餅了。
4.3 幻讀(Phantom Read)
一個事務(wù)第一次讀取數(shù)據(jù)后,另一個事務(wù)增加或者刪除了某些數(shù)據(jù),再次讀取時結(jié)果的數(shù)量發(fā)生了變化。幻讀和非重復(fù)讀有點(diǎn)類似,都是由于其他事務(wù)修改數(shù)據(jù)導(dǎo)致的結(jié)果變化。
4.4 更新丟失(Lost Update)
第一類:當(dāng)兩個事務(wù)更新相同的數(shù)據(jù)時,如果第一個事務(wù)被提交,然后第二個事務(wù)被撤銷;那么第一個事務(wù)的更新也會被撤銷。第二類:當(dāng)兩個事務(wù)同時讀取某一記錄,然后分別進(jìn)行修改提交;就會造成先提交的事務(wù)的修改丟失。
5. 隔離級別
為了解決并發(fā)訪問可能導(dǎo)致的各種問題,SQL 標(biāo)準(zhǔn)定義了 4 種不同的事務(wù)隔離級別(從低到高):
| 隔離級別 | 臟讀 | 更新丟失 | 不可重復(fù)讀 | 幻讀 |
|---|---|---|---|---|
| 讀未提交(Read Uncommitted) | 可能 | 可能 | 可能 | 可能 |
| 讀已提交(Read Committed) | – | 可能 | 可能 | 可能 |
| 可重復(fù)讀(Repeatable Read) | – | – | – | 可能 |
| 序列化(Serializable) | – | – | – | – |
- 讀未提交隔離級別最低,一個事務(wù)可以看到其他事務(wù)未提交的修改。該級別可能產(chǎn)生各種并發(fā)異常;如果一個事務(wù)已經(jīng)修改某個數(shù)據(jù),則另一個事務(wù)不允許同時修改該數(shù)據(jù),寫操作一定是按照順序執(zhí)行。
PostgreSQL消除了讀未提交級別時的臟讀。 - 讀已提交只能看到其他事務(wù)已經(jīng)提交的數(shù)據(jù),不會出現(xiàn)臟讀。
- 可重復(fù)讀可能出現(xiàn)幻讀。
MySQL中的Innodb存儲引擎和PostgreSQL在可重復(fù)讀級別消除了幻讀。 - 序列化提供最高級別的事務(wù)隔離。它要求事務(wù)只能一個接著一個地執(zhí)行,不支持并發(fā)訪問。
事務(wù)的隔離級別越高,越能保證數(shù)據(jù)的一致性;但同時會對并發(fā)帶來更大的影響。不同數(shù)據(jù)庫默認(rèn)使用的隔離級別如下:
Oracle、SQL Server以及PostgreSQL默認(rèn)使用讀已提交隔離級別;MySQL InnoDB存儲引擎默認(rèn)使用可重復(fù)讀隔離級別。
一般情況下,大多數(shù)數(shù)據(jù)庫的默認(rèn)隔離級別為讀已提交;此時,可以避免臟讀,同時擁有不錯的并發(fā)性能。盡管可能會導(dǎo)致不可重復(fù)度、幻讀以及丟失更新,但是可以通過應(yīng)用程序加鎖進(jìn)行處理。
總結(jié)
以上是生活随笔為你收集整理的MySQL 学习笔记(9)— 事务控制语句、事务属性以及并发和隔离级别的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 在哪里看中医不孕不育
- 下一篇: MySQL 学习笔记(10)—— 联结表