1. 程式人生 > 實用技巧 >MySQL教程124-MySQL執行事務的語法和流程

MySQL教程124-MySQL執行事務的語法和流程

MySQL 提供了多種儲存引擎來支援事務。支援事務的儲存引擎有 InnoDB 和 BDB,其中,InnoDB 儲存引擎事務主要通過 UNDO 日誌和 REDO 日誌實現,MyISAM 儲存引擎不支援事務。

拓展:任何一種資料庫,都會擁有各種各樣的日誌,用來記錄資料庫的執行情況、日常操作、錯誤資訊等,MySQL 也不例外。例如,當用戶 root 登入到 MySQL 伺服器,就會在日誌檔案裡記錄該使用者的登入時間、執行操作等。

為了維護 MySQL 伺服器,經常需要在 MySQL 資料庫中進行日誌操作:

  • UNDO 日誌:複製事務執行前的資料,用於在事務發生異常時回滾資料。
  • REDO 日誌:記錄在事務執行中,每條對資料進行更新的操作,當事務提交時,該內容將被重新整理到磁碟。

預設設定下,每條 SQL 語句就是一個事務,即執行 SQL 語句後自動提交。為了達到將幾個操作做為一個整體的目的,需要使用 BEGIN 或 START TRANSACTION 開啟一個事務,或者禁止當前會話的自動提交。

關於事務的自動提交在下一章節中會有講解。

執行事務的語法和流程

SQL 使用下列語句來管理事務。

1) 開始事務

BEGIN;

START TRANSACTION;

這個語句顯式地標記一個事務的起始點。

2) 提交事務

MySQL 使用下面的語句來提交事務:

COMMIT;

COMMIT 表示提交事務,即提交事務的所有操作,具體地說,就是將事務中所有對資料庫的更新都寫到磁碟上的物理資料庫中,事務正常結束。

提交事務,意味著將事務開始以來所執行的所有資料都修改成為資料庫的永久部分,因此也標誌著一個事務的結束。一旦執行了該命令,將不能回滾事務。只有在所有修改都準備好提交給資料庫時,才執行這一操作。

3) 回滾(撤銷)事務

MySQL 使用以下語句回滾事務:

ROLLBACK;

ROLLBACK 表示撤銷事務,即在事務執行的過程中發生了某種故障,事務不能繼續執行,系統將事務中對資料庫的所有已完成的操作全部撤銷,回滾到事務開始時的狀態。這裡的操作指對資料庫的更新操作。

當事務執行過程中遇到錯誤時,使用 ROLLBACK 語句使事務回滾到起點或指定的保持點處。同時,系統將清除自事務起點或到某個儲存點所做的所有的資料修改,並且釋放由事務控制的資源。因此,這條語句也標誌著事務的結束。

總結

BEGIN 或 START TRANSACTION 語句後面的 SQL 語句對資料庫資料的更新操作都將記錄在事務日誌中,直至遇到 ROLLBACK 語句或 COMMIT 語句。如果事務中某一操作失敗且執行了 ROLLBACK 語句,那麼在開啟事務語句之後所有更新的資料都能回滾到事務開始前的狀態。如果事務中的所有操作都全部正確完成,並且使用了 COMMIT 語句向資料庫提交更新資料,則此時的資料又處在新的一致狀態。

例項演示

下面通過兩個例子來演示一下 MySQL 事務的具體用法。

示例 1

下面模擬在張三的賬戶減少 500 元后,李四的賬戶還未增加 500 時,有其他會話訪問資料表的場景。由於程式碼需要在兩個視窗中執行,為了方便閱讀,這裡我們稱為 A 視窗和 B 視窗。
1) 在 A 視窗中開啟一個事務,並更新 test_db資料庫中 bank 表的資料,SQL 語句和執行結果如下:

mysql> BEGIN;  
Query OK, 0 rows affected (0.00 sec)
mysql> UPDATE bank SET currentMoney = currentMoney-500
    -> WHERE customerName='張三';
Query OK, 1 row affected (0.05 sec)
Rows matched: 1  Changed: 1  Warnings: 0

如上先執行了BEGIN開啟事務...

2) 在 B 視窗中查詢 bank 資料表中的資料,SQL 語句和執行結果如下:

mysql> SELECT * FROM bank;
+--------------+--------------+
| customerName | currentMoney |
+--------------+--------------+
| 張三         |      1000.00 |
| 李四         |         1.00 |
+--------------+--------------+
2 rows in set (0.00 sec)

從結果可以看出,雖然 A 視窗中的事務已經更改了 bank 表中的資料,但沒有立即更新資料,這時其他會話讀取到的仍然是更新前的資料。

3) 在 A 視窗中繼續執行事務並提交事務,SQL 語句和執行結果如下:

mysql> UPDATE bank SET currentMoney = currentMoney+500
    -> WHERE customerName='李四';
Query OK, 1 row affected (0.05 sec)
Rows matched: 1  Changed: 1  Warnings: 0
mysql> COMMIT;
Query OK, 0 rows affected (0.07 sec)

如上最後執行了COMMIT提交了事務....

4) 在 B 視窗中再次查詢 bank 資料表的資料,SQL 語句和執行結果如下:

mysql> SELECT * FROM bank;
+--------------+--------------+
| customerName | currentMoney |
+--------------+--------------+
| 張三         |       500.00 |
| 李四         |       501.00 |
+--------------+--------------+
2 rows in set (0.00 sec)

在 A 視窗中執行 COMMIT 提交事務後,對資料所做的更新將一起提交,其他會話讀取到的是更新後的資料。從結果可以看出張三和李四的總賬戶餘額和轉賬前保持一致,這樣資料從一個一致性狀態更新到另一個一致性狀態。

前面提到,當事務在執行中出現問題,也就是不能按正常的流程執行一個完整的事務時,可以使用 ROLLBACK 語句進行回滾,使用資料恢復到初始狀態。

在例 1 中,張三的賬戶餘額已經減少到 500 元,如果再轉出 1000 元,將會出現餘額為負數,因此需要回滾到原始狀態。如例 2 所示。

示例 2

將張三的賬戶餘額減少 1000 元,並讓事務回滾,SQL 語句和執行結果如下所示:

mysql> BEGIN;
Query OK, 0 rows affected (0.00 sec)
 
mysql> UPDATE bank SET currentMoney = currentMoney-1000 WHERE customerName='張三';
Query OK, 1 row affected (0.04 sec)
Rows matched: 1  Changed: 1  Warnings: 0
 
mysql> ROLLBACK;
Query OK, 0 rows affected (0.07 sec)
 
mysql> SELECT * FROM bank;
+--------------+--------------+
| customerName | currentMoney |
+--------------+--------------+
| 張三         |       500.00 |
| 李四         |       501.00 |
+--------------+--------------+
2 rows in set (0.00 sec)

從結果可以看出,執行事務回滾後,賬戶資料恢復到初始狀態,即該事務執行之前的狀態。

拓展

在資料庫操作中,為了有效保證併發讀取資料的正確性,提出了事務的隔離級別。在例 1 和例 2 的演示中,事務的隔離級別為預設隔離級別。在 MySQL 中,事務的預設隔離級分別有什麼會在後面講解到...

注意事項

MySQL 事務是一項非常消耗資源的功能,大家在使用過程中要注意以下幾點。

1) 事務儘可能簡短

事務的開啟到結束會在資料庫管理系統中保留大量資源,以保證事務的原子性、一致性、隔離性和永續性。如果在多使用者系統中,較大的事務將會佔用系統的大量資源,使得系統不堪重負,會影響軟體的執行效能,甚至導致系統崩潰。

2) 事務中訪問的資料量儘量最少

當併發執行事務處理時,事務操作的資料量越少,事務之間對相同資料的操作就越少。

3) 查詢資料時儘量不要使用事務

對資料進行瀏覽查詢操作並不會更新資料庫的資料,因此應儘量不使用事務查詢資料,避免佔用過量的系統資源。

4) 在事務處理過程中儘量不要出現等待使用者輸入的操作

在處理事務的過程中,如果需要等待使用者輸入資料,那麼事務會長時間地佔用資源,有可能造成系統阻塞。