MySQL 事務 異常 事務隔離的級別 事務 在你操作資料庫的同時,有可能其他用戶還會不斷地對數據進行增刪改查操作。為了避免並行進行時出現混亂,就產生了“事務”。事務就是要保證一組資料庫操作,要麼全部成功要麼全部失敗,以此來保證不混亂。 事務支持是在引擎層實現的,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]
。例如,在一個事務中為有唯一約束(包含主鍵)的欄位插入了 多條有相同值的該欄位記錄。 那麼,在mysql預設情況下就會產生錯誤,再執行ROLLBACK後就會只有未插入前的數據。如下列代碼,執行後前後查詢結果一致。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實驗通過)