事務種類
- 隱式事務
如單條 sql 語句的執行
- 顯式事務
如多條 sql 語句的執行,一般談論數據庫事務時,指的是數據庫的顯式事務
事務特性
數據庫事務具有 ACID 這4個特性
-
A —— Atomic /əˈtɒmɪk/
原子性。所有 sql 作爲一個原子工作單元執行,要麼全部執行,要麼全部不執行。這裏應該是借用了化學學科的術語概念:原子雖然在物理狀態中可以繼續細分(原子由原子核和核外電子組成),但原子在化學反應中是不可再分。
-
C —— Consistent /kənˈsɪstənt/
一致性。事務完成後,所有數據的狀態都是一致的,比如我轉賬給你100,那麼我的賬戶減去了100,你的賬戶則必定加上了100。
-
I —— Isolation /ˌaɪsəˈleɪʃn/
隔離性。每個事務做的操作必須與其它事務隔離,即便有多個事務併發執行。一個事務處理時的中間狀態對其它事務是不可見的。
-
D —— Duration /duˈreɪʃn/
持久性。事務完成後,相關的對數據庫數據的修改被持久化存儲。
數據不一致問題
多個併發執行的事務,如果操作時涉及同一條記錄數據,可能會發生問題,即併發操作可能導致數據的不一致問題,這些問題包含以下3種情形:
-
髒讀(Dirty Read)
讀取未提交數據
執行時間 事務A 事務B 1 事務開啓 2 事務開啓 修改一條記錄record(假使原來數據是純粹乾淨的,被改了,就不純粹了,髒了) 3 讀取事務B修改的那條記錄(事務B之後的事務回滾,導致了此時產生髒讀) 4 事務回滾 5 再次讀取事務B修改的那條記錄 6 事務提交 -
不可重複讀(Non Repeatable Read)
前後多次讀取,數據內容不一致
執行時間 事務A 事務B 1 事務開啓 2 讀取一條記錄record 事務開啓 3 修改事務A讀取的那條記錄 4 事務提交 5 再次讀取這條記錄record(此時發現這條記錄跟在同一個事務內之前讀取的不一致了,不能重複讀) 6 事務提交 -
幻讀(Phantom Read)
Phantom /ˈfæntəm/ ,前後多次讀取,數據記錄總數不一致
執行時間 事務A 事務B 1 事務開啓 2 查詢記錄總數count 3 事務開啓 4 增加或刪除一些記錄 5 事務提交 6 再次查詢記錄總數count(此時count比原來的大了或小了,記錄總數變了,幻讀) 7 事務提交
隔離級別
爲了避免(不是解決)上述可能出現的數據不一致問題,數據庫系統提供了隔離級別(Isolation Level)這一機制。
SQL標準定義了4種隔離級別:
1. Read Uncommitted (可以讀取未提交數據)
2. Read Committed(可以讀取已提交數據)
3. Repeatable Read(可重複讀)
4. Serializable(可串行化)
各種隔離級別分別對應可能出現的數據不一致的情況(Y標誌可能出現):
隔離級別(Isolation Level ) | 髒讀(Dirty Read) | 不可重複讀(Non Repeatable Read) | 幻讀(Phantom Read) |
---|---|---|---|
Read Uncommitted | Y | Y | Y |
Read Committed | - | Y | Y |
Repeatable Read | - | - | Y |
Serializable | - | - | - |
隔離級別雙刃劍
Read Uncommitted、Read Committed、Repeatable Read、Serializable 這4種隔離級別,按隔離級別嚴格程度劃分,Read Uncommitted隔離級別最低,Serializable隔離級別最嚴,隔離級別越嚴格,安全性越高,越能保證數據的一致性,但對併發性能的影響也越大,所謂“魚與熊掌不可兼得”吧。例如,對於Serializable隔離級別,由於事務是串行執行,即所有事務按照次序依次執行,所以效率會大大下降,應用程序的性能會急劇降低。實際項目使用時需要權衡“利弊”,比如MySQL中的InnoDB引擎,其爲了兼顧安全與性能,默認的隔離級別就是Repeatable Read,然後採取隔離級別之外的措施來避免“幻讀”的問題。