什麼是 MySQL 事務?

想象一下,你去銀行給朋友轉賬:先從你的賬戶扣錢,再往朋友賬戶加錢。這兩個步驟必須同時成功,否則錢就會莫名其妙消失或多出來。MySQL 事務就像這個場景:它是一組 SQL 操作的集合,要麼全部執行成功(提交),要麼全部失敗(回滾),不會出現“一半成功一半失敗”的中間狀態。

事務的四大特性(ACID)

事務之所以可靠,是因爲它滿足 ACID 四個核心特性,每個特性都解決了不同的問題:

1. 原子性(Atomicity)

“原子”的意思是“不可分割”。事務中的所有操作要麼全部完成,要麼一個都不做。
例子:轉賬時,“扣錢”和“加錢”必須同時成功或失敗。如果扣錢成功但加錢失敗,系統會自動回滾,讓你回到最初的狀態(比如轉賬前的賬戶餘額)。

2. 一致性(Consistency)

事務執行前後,數據必須符合業務規則。比如“總金額不變”:你轉賬 100 元,A 賬戶減 100,B 賬戶加 100,最終 A+B 的總金額和轉賬前一致。
關鍵點:一致性是事務的最終目標,由原子性和其他特性共同保證。

3. 隔離性(Isolation)

多個事務同時執行時,彼此之間不會互相干擾。比如你和朋友同時給同一個賬戶轉賬,你的操作不會影響朋友的操作,朋友的操作也不會讓你看到“未完成的中間狀態”。
注意:隔離性解決的是“併發問題”,不同的隔離級別會影響數據的可見性。

4. 持久性(Durability)

事務提交後,數據會永久保存,即使系統崩潰也不會丟失。比如轉賬成功後,就算數據庫重啓,A 和 B 賬戶的餘額也不會變。

爲什麼需要事務?典型使用場景

事務在實際業務中無處不在,核心是保證數據的“準確性”和“完整性”:

1. 銀行轉賬

  • 場景:從 A 賬戶向 B 賬戶轉 1000 元。
  • 問題:如果只扣 A 賬戶不增 B 賬戶,A 會少錢,B 沒收到錢;反之亦然。
  • 解決方案:用事務包裹 UPDATE A 賬戶UPDATE B 賬戶,成功則提交,失敗則回滾。

2. 電商訂單處理

  • 場景:用戶下單時,需要同時完成“創建訂單”和“扣減庫存”兩個操作。
  • 問題:如果只創建訂單不扣庫存,會導致“超賣”(比如 10 件商品被 100 個用戶下單,庫存顯示 10 但實際賣了 100 件)。
  • 解決方案:事務確保“下單+扣庫存”要麼同時成功,要麼同時失敗。

3. 支付系統

  • 場景:用戶支付成功後,需要更新訂單狀態、扣減用戶餘額、記錄支付流水。
  • 問題:如果其中一個步驟失敗(比如支付成功但訂單狀態沒更新),用戶可能重複支付。
  • 解決方案:事務保證所有相關操作“要麼全做,要麼全不做”。

MySQL 中如何使用事務?

MySQL 中只有 InnoDB 引擎支持事務,MyISAM 等引擎不支持。以下是基本操作步驟:

1. 顯式開啓事務

默認情況下,MySQL 可能開啓了“自動提交”(每條 SQL 語句都是獨立事務),需顯式開啓事務:

START TRANSACTION;  -- 或 BEGIN;

2. 執行 SQL 操作

在事務中執行需要保證一致性的 SQL 語句,比如轉賬示例:

-- 假設 A 賬戶 ID=1,B 賬戶 ID=2,轉賬金額=100
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
UPDATE accounts SET balance = balance + 100 WHERE id = 2;

3. 提交或回滾事務

  • 提交(COMMIT):事務中所有操作成功完成後,用 COMMIT 確認修改永久生效。
  • 回滾(ROLLBACK):如果操作出錯(比如餘額不足),用 ROLLBACK 撤銷所有修改,恢復到事務開始前的狀態。

示例:

START TRANSACTION;
-- 執行操作...
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
UPDATE accounts SET balance = balance + 100 WHERE id = 2;

-- 檢查是否有錯誤(比如餘額是否足夠)
IF 操作成功 THEN
  COMMIT;  -- 提交,修改永久生效
ELSE
  ROLLBACK; -- 回滾,撤銷所有修改
END IF;

事務隔離級別與常見問題

多個事務併發執行時,可能出現以下問題,需通過“隔離級別”解決:

1. 常見併發問題

  • 髒讀:一個事務讀取到另一個事務未提交的數據(比如 A 事務還沒提交扣錢操作,B 事務就看到了 A 扣了錢)。
  • 不可重複讀:同一事務內多次讀取同一數據,結果不同(比如 A 事務第一次讀餘額是 1000,中間 B 事務扣了錢,A 再次讀變成 900)。
  • 幻讀:同一事務內多次查詢,結果集行數不同(比如 A 事務第一次查“訂單總數”是 10 條,中間 B 事務新增了一條訂單,A 再次查變成 11 條)。

2. MySQL 事務隔離級別

MySQL InnoDB 支持 4 種隔離級別,默認是 REPEATABLE READ(可重複讀),可通過 SELECT @@tx_isolation; 查看當前級別:
- 讀未提交(READ UNCOMMITTED):最低級別,可能出現髒讀、不可重複讀、幻讀。
- 讀已提交(READ COMMITTED):避免髒讀,但可能有不可重複讀、幻讀(MySQL 中 SET TRANSACTION ISOLATION LEVEL READ COMMITTED;)。
- 可重複讀(REPEATABLE READ):MySQL 默認級別,通過多版本控制(MVCC)避免不可重複讀和幻讀(但可能有部分幻讀,具體看版本)。
- 串行化(SERIALIZABLE):最高級別,事務串行執行,完全避免併發問題,但性能最低。

注意事項

  1. 避免長事務:長事務會佔用數據庫資源,導致鎖表,影響併發性能。儘量拆分操作或縮短事務時間。
  2. 慎用自動提交:默認情況下,MySQL 可能開啓自動提交(autocommit=1),需顯式用 START TRANSACTION 控制事務範圍。
  3. 隔離級別選擇:根據業務對一致性和性能的需求選擇,比如簡單查詢用讀已提交,核心業務(如支付)用可重複讀。

總結

事務是 MySQL 保證數據一致性的核心機制,通過 ACID 特性確保操作“要麼全做,要麼全不做”。理解事務的基本概念、使用場景和操作方法,能幫助你寫出更可靠的 SQL 代碼。在實際開發中,結合業務需求選擇合適的隔離級別,避免併發問題,是保證系統穩定性的關鍵。

小夜