MySQL事務(2):事務控制

事務控制語句

MySQL默認設置下,事務都是自動提交的,即SQL執行後會立即執行commit操作。

1)常用事務語句

顯式的開啓一個事務需要使用beginstart transaction或者執行set autocommit=0,通過這些語句停止事務的自動提交。常用的事務控制語句如下,

語句 含義
start transaction、begin 顯式開啓事務
commit、commit work 提交事務,對數據庫的修改成爲永久性的
rollback、rollback work 回滾當前事務,撤銷正在執行的所有未提交的改變
savepoint identifier 設置一個標識符爲identifier的保存點
release savepoint identifier 刪除指定的事務保存點,如果該保存點不存在會拋出異常
rollback to identifier 回滾到指定保存點
set transaction 設置隔離級別,InnoDB提供的隔離級別有4種,見鎖筆記

2)差異辨析

  • start transaction和 begin
    兩個語句都可以顯式開啓事務,區別在於存儲過程。
    在存儲過程中,MySQL的分析器會將begin識別爲begin ... end,因此在存儲過程中只能使用start transaction開啓一個事務。
  • commit和 commit work
    都用於提交事務,不同之處在於commit work用於控制事務結束後的行爲是chain還是release,如果是chain方式,事務就成了鏈事務。
    可以通過設置completion_type變量的值來進行控制,默認爲0。在這種情況下,commitcommit work是等價的。
    當該變量值爲1時,commit work等價於commit work chain,表示立刻開啓一個相同隔離級別的事務。
    該變量值爲2時,等價於commit work release,事務提交後會自動斷開與服務器的連接。
    在這裏插入圖片描述
    上方操作完成後,查詢表中所有記錄,只會得到a=1的一條記錄。
    設置completion_type=1,插入a=1後對事務進行提交,插入重複記錄2時拋出異常。之後執行rollback操作,只留下一條記錄,因爲commit work chain後自動開啓一個鏈事務,第二條語句在同一個事務內,所以回滾後a=2並沒有插入到數據表中。

3)注意事項

已正確執行語句不會自動回滾

InnoDB的事務是原子的,構成事務的每條語句都會提交,或者所有語句都回滾。一條語句失敗並拋出異常時,並不會導致先前已經執行的語句回滾。必須用戶自己決定是否對已執行的語句提交或回滾,
在這裏插入圖片描述
重複插入值後,並沒有將第一次正確執行的語句所做的改變回滾。

rollback to savepoint並非結束事務

rollback to savepoint中雖然有 rollback,但是並不是真正結束事務。執行力rollback to savepoint後也需要顯式提交或回滾。
在這裏插入圖片描述
通過rollback to savepoint回滾到保存點t2,事務並沒有結束,
在這裏插入圖片描述
再運行 rollback後,事務才完整回滾。

隱式提交SQL語句

下方的SQL語句會產生一個隱式提交操作,即執行完這些語句後,會有一個隱式的commit操作,
在這裏插入圖片描述
需要注意truncate table語句是DDL,雖然和對整張表執行delete操作是一樣的,但truncate無法回滾。

分佈式事務

1)XA事務構成

分佈式事務允許多個獨立的事務資源參與到一個全局事務中。事務資源通常是關係型數據庫系統。使用分佈式事務時,InnoDB存儲引擎的事務隔離級別必須設置爲serializable

XA事務有一個或多個資源管理器、一個事務管理器和一個應用程序組成。

  • 資源管理器:提供訪問事務資源的方法,通常一個數據庫就是一個資源管理器
  • 事務管理器:協調全局事務中的各個事務,需要與所有資源管理器通信
  • 應用程序:定義事務邊界,指定全局事務中的操作

在這裏插入圖片描述
分佈式事務使用兩段式提交

  • 階段1:所有參與全局事務的節點都開始準備(PREPARE),告訴事務管理器已做好提交準備
  • 階段2:事務管理器告知資源管理器執行 rollback 或 commit。任何一個節點如果不能被正常提交,則其餘所有事務都要回滾。

相比於本地事務,分佈式事務多了一次PREPARE操作,待收到所有節點的信息後,再進行提交或回滾。

2)XA事務語法

MySQL數據庫XA事務的SQL語法如下,

在這裏插入圖片描述
在這裏插入圖片描述
單節點上運行XA事務的例子,
在這裏插入圖片描述

事務控制不良習慣

1)循環中提交

大多數情況下,MySQL都會開啓自動提交,如果遇到循環執行的SQL語句,相當於每輪循環中都會進行一次提交。下面兩個事務過程的執行時相同的,

  1. 自動提交開啓的狀態下,顯式的在每輪循環中提交
    在這裏插入圖片描述
  2. 自動提交開啓狀態下,未顯式在每輪循環中提交
    在這裏插入圖片描述
  3. 自動提交開啓狀態下,存儲過程使用start transaction
    在這裏插入圖片描述

對上述三個過程進行調用,
在這裏插入圖片描述
相比於load1和load2中count次提交,存儲過程load3只進行了一次提交。如果對load2的調用過程進行調整也可以達到 load3的效果,
在這裏插入圖片描述

2)不關注一個事務中語句順序

根據兩階段鎖,整個事務中涉及的鎖,需要等待事務提交時纔會釋放。同一個事務中,把沒鎖或鎖定範圍小的語句先執行,鎖定範圍大的語句後執行

3)不關注不同事務訪問資源的順序

死鎖原因中有兩條與不同事務訪問資源的順序有關,

  • 不同線程併發訪問同一張表的多行數據,未按順序訪問導致死鎖
  • 不同線程併發訪問多個表時,未按順序訪問導致死鎖

4)不關注事務隔離級別

如果完全不關注業務使用的 MySQL 是什麼隔離級別,可能會降低程序的併發能力或者導致死鎖。

比如業務場景完全能接受幻讀,如果要求更高的 QPS,使用 RR 隔離級別顯然不是最好的選擇,因此可以改爲 RC 隔離級別。而如果業務使用的是 RR 隔離級別,可能由於間隙鎖導致死鎖(可參考MySQL鎖筆記中的例子),因此也應該在程序編寫時關注 RR 隔離級別下是否會有間隙鎖。

5)混合使用存儲引擎

在事務中混合使用事務型(比如 InnoDB)和非事務型(比如 MyISAM)表,如果是正常提交是什麼問題。但是,如果該事務回滾了,事務型的表可以正常回滾,而非事務型的表的變更就無法回滾了。這種情況就會導致數據不正常,並且事務最終的結果也難以確定。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章