MySQL 事務 異常 事務隔離的級別
MySQL 事務 異常 事務隔離的級別
事務
在你操作資料庫的同時,有可能其他使用者還會不斷地對資料進行增刪改查操作。為了避免並行進行時出現混亂,就產生了“事務”。事務就是要保證一組資料庫操作,要麼全部成功要麼全部失敗,以此來保證不混亂。
事務支援是在引擎層
實現的,MySQL支援多系統,不是所有引擎都支援事務。
事務的特性(ACID)
- Atomicity(原子性):原子即不可分割,即事務是進行資料處理的基本單位
- Consistency(一致性):事務使資料庫從一種狀態到另一種狀態,且資料庫的約束性不被破壞
- Isolation(隔離性):指事務之間保持獨立性,不被其他事務影響的特性。分為四個隔離等級
- Durability(永續性):事務提交後對資料庫的修改時“持久的”,永續性是用過日誌來實現的(回滾日誌+重做日誌)。即使發生故障,資料修改依然有效,因為當事務完成,日誌就會被更新,我們依然可以恢復到最後一次成功提交事務時的狀態。
原子性是基礎,一致性是約束,隔離性是手段,永續性是目的。
事務操作方式
Mysql預設autocommit = 1
,compelation = 0
autocommit = 1
:每條SQL都自動提交
autocommit = 0
:不論是否使用START TRANSACTON
或BEGIN
,總要使用commit
才能提交。有些客戶端框架會預設連線後先執行set autocommit = 0
儘量不要長事務,詳見"可重複讀的實現"
compelation = 0
:執行commit僅提交事務
compelation = 1
:commit時相當於commit and chain
,開啟鏈式事務,提交事務後開啟一個相同的事務
compelation = 2
: commit時相當於commit and release
,提交後會自動斷開伺服器連線
在MySQL預設的設定下
-
使用
START TRANSACTION
或BEGIN
顯式開啟一個事務,然後再用COMMIT
提交 -
使用
ROLLBACK
進行回滾,或者回滾到ROLLBACK TO [SAVEPOINT]
SELECT * FROM t; ... BEGIN; INSERT INTO t id VALUES 1; INSERT INTO t id VALUES 1; ROLLBACK; SELECT * FROM t;
需要注意的是,插入錯誤後只有手動
ROLLBACK
後才會執行後前後查詢結果一致
,不執行ROLLBACK的結果是後面的查詢結果會比前面多一條id為1的記錄。
三種異常
- 髒讀:事務並行進行時,事務A讀到了事務B中新增但未提交的內容
- 不可重複讀:事務並行進行,事務A對錶進行查詢時事務B對錶某行進行修改,導致事務A發現兩次讀取時的結果不同。
- 幻讀:事務並行進行,事務A進行查詢時事務B對錶新增資料,導致事務A兩次讀取時讀到更多的資料。
用於解決異常的四個事務隔離級別
隔離得越嚴實,效率就會越低,我們需要在生產中尋找一個平衡點,按業務決定。
對於隔離級別從低到高分別是
-
讀未提交(READ UNCOMMIT) --- 允許讀到未提交的資料 --- 不使用鎖,無法避免三種異常
-
讀已提交(READ COMMIT) --- 只能讀到已提交的資料 --- 其本身可避免髒讀(也是Oracle和SQL
Server預設的隔離級別) --- 可以編寫帶鎖的SQL語句來避免“不可重複讀”和“幻讀”
-
可重複讀(REPEATABLE READ) --- 事務在執行期間看到的資料必須前後一致 --- 避免 “髒讀”和“不可重複讀” (是MySQL預設的隔離級別)
-
可序列化(SERIALIZABLE)--- 將所有事務序列化,是最高隔離等級,可以避免所有異常,但是犧牲了併發性
隔離級別效用說明例題:
- 讀未提交:V1=2 V2=2 V3=2
- 讀已提交:V1=1 V2=2 V3=2
- 可重複讀:V1=1 V2=1 V3=2 (事務在執行期間看到的資料必須一致)
- 可序列化:V1=2 V2=2 V3=2 (序列化時B在執行“將1改為2”時會被鎖住,直到事務A被提交)
查詢mysql當前的隔離等級
mysql> show variables like 'transaction_isolation';
+-----------------------+-----------------+
| Variable_name | Value |
+-----------------------+-----------------+
| transaction_isolation | REPEATABLE-READ |
+-----------------------+-----------------+
1 row in set (0.02 sec)
“可重複讀”的實現
-
隔離的實現主要有
讀寫鎖
和多版本併發處理(MVCC)
兩種方式。(因為讀寫鎖降低了事務併發效率,為了讓讀寫之間也不衝突,就發明了MVCC) -
事務隔離的實現拓展閱讀見此處,有一定了解後再整理自己的版本
-
下面簡單介紹MVCC利用ReadView(快照)實現可重複讀
-
MySQL中每條記錄在更新的時候都會同時記錄一條回滾日誌
在將1依次改為2,3,4的過程中,回滾日誌有如下記錄
ReadView_A:將2改為1
ReadView_B:將3改為2
ReadView_C:將4改為3
而當前:
值為4
這就讓同一條記錄在系統中可以有多個版本
,這就是MVCC,此時如果有"將4改為5"的事務,它並不會影響回滾日誌中的A、B、C。
-
儘量不要使用
長事務
:長事務意味著有很多舊的ReadView(影響回滾空間,5.5之前甚至有可能回滾空間大於真實資料),這會導致佔用大量的儲存空間,而且長事務還會佔用鎖資源,有可能拖垮整個庫。 -
刪除回滾日誌:預設情況下,系統會自行判斷,當沒有事務需要用到這些回滾日誌時就會被刪除。在上述例子中,如果修改為4之後就commit(相當短的事務),即會造成“沒有事務需要用到這些回滾日誌”,上述回滾日誌就會被刪除。
也就是說
事務未提交前可以回滾,提交後回滾日誌會被刪除(5.7實驗通過)