本文 AI 產出,尚未審核

MySQL 交易(Transaction)

START TRANSACTION / COMMIT / ROLLBACK


簡介

在資料庫開發中,資料完整性一致性是最根本的要求。即使是最簡單的增刪改操作,也可能因為網路斷線、程式錯誤或同時寫入衝突而留下不完整或不正確的資料。
MySQL 透過 交易(Transaction) 機制,讓一組相關的 SQL 敘述能夠 原子性(atomic)地執行:要麼全部成功,要麼全部失敗,資料庫永遠不會處於半完成的狀態。

本篇文章聚焦於 MySQL 中最常使用的三個指令:

  • START TRANSACTION(或 BEGIN
  • COMMIT
  • ROLLBACK

我們將從概念說明、實作範例、常見陷阱與最佳實踐,最後延伸到真實的應用情境,幫助你在日常開發中正確、有效地使用交易。


核心概念

1. 什麼是交易?

交易是一組 邏輯上相關 的 SQL 語句,具備以下四大特性(ACID):

特性 說明
Atomic(原子性) 所有語句要麼全部成功,要麼全部失敗。
Consistency(一致性) 交易執行前後,資料庫必須保持一致的狀態。
Isolation(隔離性) 交易之間互不干擾,避免讀到未提交的資料。
Durability(永久性) 一旦提交(COMMIT),變更即永久寫入磁碟,即使系統崩潰也不會遺失。

小提醒:MySQL 的預設儲存引擎 InnoDB 完全支援 ACID;若使用 MyISAM,則不支援交易。

2. 開始交易:START TRANSACTION / BEGIN

START TRANSACTION;
-- 或者簡寫
BEGIN;

兩者等價,會把連線的 自動提交模式(autocommit) 暫時關閉,直到執行 COMMITROLLBACK 為止。此時,所有後續的 DML(INSERT、UPDATE、DELETE)都會被暫存於交易緩衝區。

3. 提交交易:COMMIT

COMMIT;

COMMIT 會把交易緩衝區的變更永久寫入磁碟,並自動恢復自動提交模式。此時其他連線才能看到這些變更。

4. 回滾交易:ROLLBACK

ROLLBACK;

若在交易過程中發生錯誤,或是業務邏輯判斷需要取消操作,執行 ROLLBACK 就會將所有變更撤銷,回到交易開始前的狀態。


程式碼範例

以下示範 5 個常見情境,讓你快速掌握交易的使用方式。

範例 1:簡單的扣款與入帳(原子性)

START TRANSACTION;

UPDATE accounts SET balance = balance - 100
WHERE user_id = 1 AND balance >= 100;

UPDATE accounts SET balance = balance + 100
WHERE user_id = 2;

COMMIT;

說明:若第一筆 UPDATE 因餘額不足而影響 0 行,整筆交易仍會提交。實務上應先檢查 ROW_COUNT(),若不足則 ROLLBACK

範例 2:失敗時回滾(錯誤處理)

START TRANSACTION;

INSERT INTO orders (user_id, total) VALUES (1, 250);
SET @order_id = LAST_INSERT_ID();

INSERT INTO order_items (order_id, product_id, qty) VALUES
(@order_id, 101, 2),
(@order_id, 102, 1);

-- 假設第二筆 INSERT 因外鍵違反失敗
-- MySQL 會拋出錯誤,我們在應用程式端捕獲後執行 ROLLBACK

ROLLBACK;

說明:在程式碼(如 PHP、Node.js)捕獲例外後,務必呼叫 ROLLBACK,避免資料遺留下半完成的紀錄。

範例 3:使用 SAVEPOINT 與部分回滾

START TRANSACTION;

INSERT INTO inventory (product_id, qty) VALUES (200, 50);
SAVEPOINT after_inventory;

INSERT INTO shipments (product_id, qty, dest) VALUES (200, 30, 'TW');
-- 假設運送資料有誤,只想回到 inventory 的狀態
ROLLBACK TO SAVEPOINT after_inventory;

COMMIT;

說明SAVEPOINT 允許在同一筆交易內設定多個回滾點,靈活控制哪一段需要撤銷。

範例 4:設定交易隔離等級(Isolation Level)

-- 讀取未提交的資料(Dirty Read)-- 只在測試環境使用
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
START TRANSACTION;

SELECT balance FROM accounts WHERE user_id = 3;

COMMIT;

說明:MySQL 支援四種隔離等級(READ UNCOMMITTED、READ COMMITTED、REPEATABLE READ、SERIALIZABLE),預設為 REPEATABLE READ,大多數情況不需要更改。

範例 5:自動提交模式的切換

-- 關閉自動提交,等同於每次手動 START TRANSACTION
SET autocommit = 0;

UPDATE products SET stock = stock - 5 WHERE product_id = 400;
UPDATE orders SET status = 'processed' WHERE order_id = 789;

COMMIT;   -- 必須手動提交
SET autocommit = 1;   -- 恢復預設

說明:直接關閉 autocommit 會讓所有後續語句自動納入同一筆交易,適合批次腳本或長時間執行的維護作業。


常見陷阱與最佳實踐

陷阱 可能的影響 解決方式
忘記 COMMIT 交易永遠不會釋放鎖,導致其他連線阻塞。 確保每條 START TRANSACTION 最終都有 COMMITROLLBACK,可在程式碼中使用 finally 區塊保證。
READ COMMITTED 以外的隔離等級下使用長交易 產生大量的 undo log,佔用磁碟空間,甚至觸發「死鎖」。 盡量讓交易保持短小,只包住必要的語句。
混用自動提交與手動交易 可能導致部分語句提前提交,破壞原子性。 統一使用手動交易,或在需要時暫時關閉 autocommit
忽略錯誤回傳 交易失敗卻仍執行 COMMIT,造成不一致資料。 在程式層捕捉例外,發生錯誤立即 ROLLBACK
使用 MyISAM 引擎 完全不支援交易,所有 START TRANSACTION 會被忽略。 改用 InnoDB,或確認表格已轉換為支援交易的引擎。

最佳實踐

  1. 最小化交易範圍:只把必須一起成功的語句放入同一筆交易,減少 lock 持有時間。
  2. 明確檢查受影響列數ROW_COUNT()FOUND_ROWS() 能幫助判斷是否真的執行成功。
  3. 使用 SAVEPOINT:在複雜流程中加入回滾點,避免整筆交易回滾。
  4. 設定合理的隔離等級:大多數應用使用預設的 REPEATABLE READ;若讀取大量報表,可考慮 READ COMMITTED 以降低快照成本。
  5. 監控與日誌:將每次 START TRANSACTIONCOMMITROLLBACK 記錄到應用層日誌,便於排錯與審計。

實際應用場景

場景 為何需要交易 典型 SQL 流程
電商訂單處理 同時扣減庫存、產生訂單、更新客戶積分,必須全部成功。 START TRANSACTION → INSERT orders → UPDATE inventory → UPDATE members → COMMIT
銀行轉帳 兩筆帳戶餘額的變更必須同步完成,避免出現「負餘額」或「金額遺失」。 START TRANSACTION → UPDATE from_account → UPDATE to_account → IF ROW_COUNT()=2 THEN COMMIT ELSE ROLLBACK
批次匯入資料 大量寫入時若發現資料錯誤,需要一次回滾,保證匯入結果全或無。 SET autocommit=0; START TRANSACTION; LOAD DATA ...; IF error THEN ROLLBACK ELSE COMMIT; SET autocommit=1;
多階段審批流程 每個審批階段的變更需保留在同一筆交易中,確保流程不被中斷。 START TRANSACTION → UPDATE approvals → INSERT logs → COMMIT
報表快照 為了避免讀到未提交的變更,使用 READ COMMITTEDREPEATABLE READ 產生一致性快照。 SET TRANSACTION ISOLATION LEVEL REPEATABLE READ; START TRANSACTION; SELECT ...; COMMIT;

總結

  • 交易是保證資料完整性的核心機制START TRANSACTIONCOMMITROLLBACK 三指令構成了最基本的使用方式。
  • 充分理解 ACID 四大特性,才能在設計資料庫操作時正確運用交易。
  • 常見的陷阱包括忘記提交、長時間持有鎖、混用自動提交等,最佳實踐是保持交易短小、明確檢查執行結果、適時使用 SAVEPOINT
  • 在電商、金融、批次匯入等實務場景中,交易是不可或缺的保護層,能讓系統在面對錯誤或異常時仍然維持 一致性可靠性

掌握了這些概念與技巧,你就能在 MySQL 上建立穩健、可擴充的資料庫應用,讓業務邏輯與資料安全同時得到保障。祝開發順利!