MySQL事務概述-1
事務是資料庫區別於檔案系統最重要的特性之一。事務可由一條非常簡單的SQL語句組成,也可以由一組複雜的SQL語句組成。事務是訪問並更新資料庫中各種資料項的一個程式執行單元。在事務操作中,要麼都做修改,要麼都不做,這就是事務的目的。
MySQL的儲存引擎中,INNODB支援事務特性,這裡主要講述INNODB的事務特性。
INNODB儲存引擎完全符合事務的ACID特性:
- 原子性(atomicity)
- 一致性(consistency)
- 隔離性(isolation)
- 永續性(durability)
原子性: 是指整個資料庫事務是不可分割的工作單位。只有使事務中所有的資料庫操作都執行成功,才能整個事務成功。事務中任何一個SQL語句執行失敗,已經執行成功的SQL語句必須撤銷,資料庫狀態應該退回到執行事務之前的狀態。事務是最小的工作單元,構成事務的DML語句,要麼全部執行成功,要麼全部失敗,這就是事務的原子性。
一致性: 在事務的執行前後,不能破壞資料庫的完整性約束條件。
隔離性:多個事務並行執行,一個事務的修改對其他事務是不可見的,好似是序列執行的。INNODB使用鎖來保證事務的隔離性。
永續性:事務一旦提交,所做的修改時持久的,不會因為資料庫的宕機,恢復等丟失事務的修改。
事務的分類(摘自Inside君的《MySQL技術內幕-INNODB儲存引擎》):
- 扁平事務(float transactions)
- 帶有儲存點的扁平事務(flat transactions with savepoint)
- 鏈事務(Chained Transactions)
- 巢狀事務(Nested Transactions)INNODB儲存引擎不支援
- 分散式事務(Distributed Transactions)
扁平事務:是事務型別中最簡單的一種,但在實際中,用的最多。在扁平事務中,所有的操作都處於同一層次,其由begin開始,由commit或者rollback結束,其間操作是原子的,要麼都執行,要麼全部回滾。
#扁平事務的基本形式如下: BEGINE WORK; operation1; operation2; ..... commit OR rollback;
帶有儲存點的扁平事務: 在扁平事務中,事務中的SQL語句要麼全部執行,要麼全部回滾,但是有時operation1操作執行成功,operation2也執行了,這時候我們想回滾到operation1操作執行之後的狀態?引入了儲存點的概念,只要在operation1執行之後設定儲存點,回滾時指定對應的儲存點,就可以回滾到指定的儲存點的狀態:
mysql> select * from tb1; +---+ | a | +---+ | 1 | | 2 | | 4 | +---+ 3 rows in set (0.00 sec) mysql> begin; Query OK, 0 rows affected (0.00 sec) mysql> insert into tb1 select 5; Query OK, 1 row affected (0.00 sec) Records: 1 Duplicates: 0 Warnings: 0 mysql> savepoint test1; #設定儲存點1 Query OK, 0 rows affected (0.00 sec) mysql> insert into tb1 select 7; Query OK, 1 row affected (0.00 sec) Records: 1 Duplicates: 0 Warnings: 0 mysql> savepoint test2; #設定儲存點2 Query OK, 0 rows affected (0.00 sec) mysql> select * from tb1; +---+ | a | +---+ | 1 | | 2 | | 4 | | 5 | | 7 | +---+ 5 rows in set (0.00 sec) mysql> rollback to test1; #回滾到儲存點1 Query OK, 0 rows affected (0.00 sec) mysql> select * from tb1; +---+ | a | +---+ | 1 | | 2 | | 4 | | 5 | +---+ 4 rows in set (0.00 sec) mysql>儲存點例項
上面的例項中我們最先開始用begin開啟了一個事務,然後又回滾到了儲存點test1,需要注意的是這個事務並沒有結束,若需要結束需要執行commit或者rollback!
鏈事務:
儲存點事務的一種變種。儲存點事務在系統崩潰時,所有的儲存點都是易失的,即系統恢復時,事務需要從開始出重新執行,而不能從最近的儲存點繼續執行。
鏈事務指的是在提交事務時,釋放不需要的資料物件,將必要的處理上下文隱式地傳給下一個要開始的事務。提交事務和開始下一個事務將合併為一個原子操作。即下一個事務將看到上一個事務的結果,就好象在一個事務中進行一樣。
鏈事務與帶有儲存點的事務不同,帶有儲存點的事務能回滾到任意正確的儲存點。而鏈事務中的回滾僅限於當前儲存點。
鏈事務例項見下面:
巢狀事務:
是一個層次結構框架。由一個頂層事務控制各個層次的事務。頂層事務之下巢狀的事務被稱為子事務,其控制每一個區域性的變換。
巢狀事務的定義如下:
- 巢狀事務是由若干事務組成的一棵樹,子樹既可以是巢狀事務,也可以是扁平事務。
- 處在葉子節點的是扁平事務。但是每個事務從根到葉節點的距離可以是不同的。
- 位於根節點的事務稱為頂層事務,其他事務稱為子事務。事務的前驅稱為父事務,事務的下一層事務稱為兒子事務。
- 子事務既可以提交也可以回滾。但是它的提交操作並不馬上生效,除非其父事務已經提交,任何子事務都在頂層事務提交後才能真正的提交。
- 樹中的任意一個事務的回滾會引起它的所有子事務一同回滾,故子事務僅保留ACI特性,不具有D特性。
MySQL不支援巢狀事務。
分散式事務
分散式事務是在分散式環境下執行的扁平事務。
事務控制語句
在MySQL的命令列預設設定下,事務都是自動提交的,即執行語句後就會馬上執行commit操作。
mysql> show variables like "autocommit"; +---------------+-------+ | Variable_name | Value | +---------------+-------+ | autocommit | ON | +---------------+-------+ 1 row in set (0.01 sec) #預設情況自動提交時開啟的,可以設定為關閉。
#事務控制語句如下
- start transaction | begin 顯式開啟一個事務。(在儲存過程中MySQL會自動將begin識別為begin....and,因此在儲存過程中開啟事務,需要使用start transaction)
- commit | commit work 提交事務
- rollba | rollback work 回滾事務
- savepoint 建立儲存點
- release savepoint identifier : 刪除一個儲存點,當儲存點不存在時,會報出異常
- rollback to 【savepoint】 identifier: 回滾到某一個儲存點
- set transaction leve xxxx: 設定事務的隔離級別
commit和commit work語句基本一致,都是用來提交事務。不同之處在於commit work用來控制事務結束後的行為是chain還是release的。如果是chain,那麼就是鏈事務。
值(completion_type的取值) | 描述 |
NO_CHAIN (或0) |
COMMIT 並且 ROLLBACK 不受影響。這是預設值。 |
CHAIN (或1) |
commit和rollback之後,會自動開啟一個事務。 |
RELEASE (或2) |
commit和rollback之後,會終止當前會話的連線。 |
鏈事務例項:
mysql> select * from tb2; +------+ | a | +------+ | 10 | | 20 | +------+ 2 rows in set (0.00 sec) mysql> set @@completion_type=1; #設定為1 Query OK, 0 rows affected (0.00 sec) mysql> begin; #顯式開啟一個事務 Query OK, 0 rows affected (0.00 sec) mysql> insert into tb2 select 30; #插入數值30 Query OK, 1 row affected (0.00 sec) Records: 1 Duplicates: 0 Warnings: 0 mysql> commit; #提交事務 Query OK, 0 rows affected (0.00 sec) mysql> insert into tb2 select 40; #插入40 Query OK, 1 row affected (0.00 sec) Records: 1 Duplicates: 0 Warnings: 0 mysql> rollback; #回滾事務 Query OK, 0 rows affected (0.00 sec) mysql> select * from tb2; #結果看到只回滾了插入40的事務,也就是說上面的commit提交之後,又開啟了一個事務。 +------+ | a | +------+ | 10 | | 20 | | 30 | +------+ 3 rows in set (0.00 sec) mysql>
當數值設定為2時:
mysql> set @@completion_type=2; Query OK, 0 rows affected (0.00 sec) mysql> select * from tb2; +------+ | a | +------+ | 10 | | 20 | | 30 | +------+ 3 rows in set (0.00 sec) mysql> begin; Query OK, 0 rows affected (0.00 sec) mysql> insert into tb2 select 40; Query OK, 1 row affected (0.00 sec) Records: 1 Duplicates: 0 Warnings: 0 mysql> commit; #事務提交之後 Query OK, 0 rows affected (0.00 sec) mysql> select @@version; #再次查詢會有重新連線的提示,說明上次事務提交之後,斷開了當前會話的連線 ERROR 2006 (HY000): MySQL server has gone away No connection. Trying to reconnect... Connection id: 86 Current database: mytest +------------+ | @@version | +------------+ | 5.7.22-log | +------------+ 1 row in set (0.00 sec) mysql>
對事物的操作統計:
【待續】