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