MySQL 支持對 MyISAM 和 MEMORY 存儲引擎的表進行表級鎖定,對 BDB 存儲引擎的表進行頁級鎖定,對 InnoDB 存儲引擎的表進行行級鎖定。默認情況下,表鎖和行鎖都是自動獲得的,不需要額外的命令。但是在有的情況下,用戶需要明確地進行鎖表或者進行事務的控制,以便確保整個事務的完整性,這樣就需要使用事務控制和鎖定語句來完成。
1) LOCK TABLE 和 UNLOCK TABLE
LOCK TABLES 可以鎖定用於當前線程的表。如果表被其他線程鎖定,則當前線程會等待,直到可以獲取所有鎖為止。
UNLOCK TABLES 可以釋放當前線程獲得的任何鎖定。當前線程執行另一個 LOCK TABLES 時,或當與服務器的連接被關閉時,所有由當前線程鎖定的表被隱含的解鎖,具體語法如下
LOCK TABLES
tbl_name [AS alias] {READ [LOCAL]|[LOW_PRIORITY] WRITE}
[,tbl_name [AS alias] {READ [LOCAL]|[LOW_PRIORITY] WRITE}] ...
UNLOCK TABLES
2) 事務控制
MySQL 通過 SET AUTOCOMMIT、START TRANSACTION、COMMIT 和 ROLLBACK 等語句支持本地事務,具體語法如下
START TRANSACTION|BEGIN [WORK]
COMMIT [WORK] [AND [NO] CHAIN] [[NO] RELEASE]
ROLLBACK [WORK] [AND [NO] CHAIN] [[NO] RELEASE]
SET AUTOCOMMIT={0|1}
START TRANSACTION 或 BEGIN 語句可以開始一項新的事務。
COMMIT 和 ROLLBACK 用來提交或者回滾事務
CHAIN 和 RELEASE 子句分別用來定義在事務提交或者回滾之后的操作,CHAIN 會立即啟動一個新事物,並且和剛才的事務具有相同的隔離級別,RELEASE 則會斷開和客戶端的連接。
SET AUTOCOMMIT 可以修改當前連接的提交方式,如果設置了 SET AUTOCOMMIT = 0 ,則設置之后的所有事務都需要通過明確地命令進行提交或者回滾。
- 默認情況下,MySQL是自動提交的,如果需要通過明確的 Commit 和 Rollback 來提交和回滾事務,那么就需要通過明確地事務控制命令來開始事務,這是和 Oracle 的事務管理明顯不同的地方。如果應用是從 Oracle 數據庫遷移到 MySQL 數據庫,則需要確保應用中是否對事務進行了明確地管理。
- 如果只是對某些語句需要進行事務控制,則使用 START TRANSACTION 語句開始一個事務比較方便,這樣事務結束之后可以自動回到自動提交的方式,如果希望所有事務都不是自動提交的,那么通過修改 AUTOCOMMIT 來控制事務比較方便,這樣不用在每個事務開始的時候再執行 START TRANSACTION 語句。
- 如果在鎖表期間,用 START TRANSACTION 命令開始一個新事物,會造成一個隱含的 UNLOCK TABLES 被執行。
- 在同一個事務中,最好不使用不同存儲引擎的表,否則 ROLLBACK 時需要對非事務類型的表進行特別的處理,因為 COMMIT、ROLLBACK 只能對事務類型的表進行提交和回滾。
- 對 LOCK 方式加的表鎖,不能通過 ROLLBACK 進行回滾。
- 通常情況下,只對提交的事務記錄到二進制的文件中,但是如果一個事務中包含非事務類型的表,那么回滾操作也會被記錄到二進制日志中,以確保非事務類型表的更新可以被復制到從數據庫(Slave)中。
- 和 Oracle 的事務管理相同,所有的 DDL 語句是不能回滾的,並且部分的 DDL 語句會造成隱式的提交。
- 在事務中可以通過定義 SAVEPOINT,指定回滾事務的一個部分,但是不能指定提交事務的一個部分。對於復雜的應用,可以定義多個不同的 SAVEPOINT,滿足不同的條件時,回滾不同的 SAVEPOINT。需要注意的是,如果定義了相同名字的 SAVEPOINT,則后面定義的 SAVEPOINT 會覆蓋之前的定義。對於不再需要使用的 SAVEPOINT,可以通過 RELEASE SAVEPOINT 命令刪除 SAVEPOINT,刪除后的 SAVEPOINT 不能再執行 ROLLBACK TO SAVEPOINT 命令。
3) 分布式事務
- MySQL 從5.0.3開始支持分布式事務,當前分布式事務只支持 InnoDB 存儲引擎。一個分布式事務會涉及多個行動,這些行動本身是事務性的。所有行動都必須一起成功完成,或者一起被回滾。
- 在 MySQL 中,使用分布式事務的應用程序設計一個或多個資源管理器和一個事務管理器。
資源管理器(RM)用於提供通向事務資源的途徑。數據庫服務器是一種資源管理器,該管理器必須可以提交或回滾由 RM 管理的事務。例如,多台 MySQL 數據庫作為多台資源管理器或者幾台 MySQL 服務器和幾台 Oracle 服務器作為資源管理器。
事務管理器(TM)用於協調作為一個分布式事務一部分的事務。TM 與管理每個事務的 RMs 進行通信。在一個分布式事務中,各個單個事務均是分布式事物的“分支事務”。分布式事務和各分支通過一種命名方法進行標識。
- MySQL 執行 XA MySQL 時,MySQL 服務器相當於一個用於管理分布式事務中的 XA 事務的資源管理器。與 MySQL 服務器連接的客戶端相當於事務管理器。
- 要執行一個分布式事務,必須知道這個分布式事務涉及了哪些資源管理器,並且把每個資源管理器的事務執行到事務可以被提交或回滾時。根據每個資源管理器報告的有關執行情況的內容,這些分支事務必須作為一個原子性操作全部提交或回滾。要管理一個分布式事務,必須要考慮任何組件或連接網絡可能會出現的故障。
- 用於執行分布式事務的過程使用兩階段進行提交,發生時間由分布式事務的各個分支需要進行的行動已經被執行之后。
在第一階段,所有的分支被預備好。即他們被 TM 告知要准備提交。通常,這意味着用於管理分支的每個 RM 會記錄對於被穩定保存的分支的行動。分支指示是否他們可以這么做。這些結果被用於第二階段。
在第二階段,TM 告知 RMs 是否要提交或回滾。如果在預備分支時,所有的分支指示他們能夠提交,則所有的分支被告知要提交。如果在預備時,有任何分支指示它將不能提交,則所有的分支被回滾。
在有些情況下,一個分布式事務可能會使用一階段提交。例如,當一個事務管理器發現,一個分布式事務只由一個事務資源組成(即單一分支),則該資源可以被告知同時進行預備和提交。
- 分布式事務(XA 事務)的語法
啟動:
XA {START|BEGIN} xid [JOIN|RESUME]
XA START xid 用於啟動一個帶給定 xid 值的 XA 事務。每個 XA 事務必須有一個唯一的 xid 值,因此該值當前不能被其他的 XA 事務使用。xid 是一個 XA 事務標識符,用來唯一標識一個分布式事務。xid 值有客戶端提供,或由 MySQL 服務器生成。xid 值包含 1~3個部分:
xid: gtrid[, bqual[, formatID]]
gtrid是一個分布式事務標識符,相同的分布式事務應該使用相同的 gtrid,這樣可以明確知道 XA 事務屬於哪個分布式事務。
bqual 是一個分支限定符,默認值是空串。對於一個分布式事務中的每個分支事務,bqual 值必須是唯一的。
formatID 是一個數字,用於標識由 gtrid 和 bqual 值使用的格式,默認值是1。
使事務進入 PREPARE 狀態,也就是兩階段提交的第一個提交階段:
XA END xid [SUSPEND [FOR MIGRATE]]
XA PREPARE xid
提交或者回滾具體的事務分支,也就是兩階段提交的第二個提交階段,分支事務被實際的提交或者回滾:
XA COMMIT xid [ONE PHASE]
XA ROLLBACK xid
返回當前數據庫終於處於 PREPARE 狀態的分支事務的詳細信息:
XA RECOVER
- 分布式的關鍵在於如何確保分布式事務的完整性,以及在某個分支出現問題時的故障解決。XA 的相關命令就是提供給應用如何在多個獨立的數據庫之間進行分布式事務的管理,包括啟動一個分布式事務、使事務進入准備階段以及事務的實際提交回滾操作等。
- 雖然 MySQL 支持分布式事務,但是如果分支事務在達到 PREPARE 狀態時,數據庫異常重新啟動,服務器重新啟動以后,可以繼續對分支事務進行提交或回滾操作,但是提交的事務沒有寫 binlog,存在一定的隱患,可能導致使用 binlog 恢復丟失部分數據。如果存在復制的數據庫,則有可能導致主從數據庫的數據不一致。
- 使用 mysqlbinlog 查看 binlog,可以確認最后提交的這個分支事務並沒有記錄到 binlog 中,因為復制和災難恢復都是依賴於 binlog的,所以 binlog 的確實會導致復制環境的不同步,以及使用 binlog 恢復丟失部分數據。