事務是資料庫區別於文件系統的核心特性,保證數據在並發、故障場景下的一致性。本文以支付寶轉賬為例,圖解 MySQL 事務的四大特性 (ACID)、顯式事務控制語句、保存點機制及最佳實踐。
張三轉 1000 元給李四,涉及兩條 SQL:
UPDATE account SET balance = balance - 1000 WHERE id = 1; -- 張三扣款
UPDATE account SET balance = balance + 1000 WHERE id = 2; -- 李四入賬
若第一條成功、第二條執行前發生故障 (網線被挖斷、進程崩潰),張三錢少了、李四沒收到,**數據不一致**。事務機制確保:**要麼全成功,要麼全失敗,不存在中間態**。
| 特性 | 英文 | 通俗解釋 |
|---|---|---|
| 原子性 | Atomicity | 事務內所有操作是不可分割的原子單元,全做或全不做 |
| 一致性 | Consistency | 事務執行前後,數據庫從一個一致性狀態變換到另一個一致性狀態 (如轉賬前後總金額不變) |
| 隔離性 | Isolation | 並發事務之間互不干擾,MySQL 通過鎖 + MVCC 實現 (READ COMMITTED / REPEATABLE READ 等級別) |
| 持久性 | Durability | 事務提交後,修改永久保存,即使數據庫崩潰重啟也能通過 Redo Log 恢復 |
autocommit=ON)。START TRANSACTION; 或 BEGIN; (標記事務起點)。COMMIT; (持久化所有修改)。ROLLBACK; (撤銷事務起點以來所有修改)。START TRANSACTION;
UPDATE account SET balance = balance - 1000 WHERE id = 1;
UPDATE account SET balance = balance + 1000 WHERE id = 2;
ROLLBACK; -- 故意回滾,模擬業務邏輯判斷失敗
結果:張三、李四餘額均不變。
START TRANSACTION;
UPDATE account SET balance = balance - 1000 WHERE id = 1;
UPDATE account SET balance = balance + 1000 WHERE id = 2;
COMMIT; -- 確認無誤,持久化
結果:張三 -1000,李四 +1000,總額守恆。
START TRANSACTION;
UPDATE account SET balance = balance - 1000 WHERE id = 1;
SAVEPOINT sp1; -- 設置保存點
UPDATE account SET balance = balance + 1000 WHERE id = 2; -- 假設這條報錯或業務判斷需撤銷
ROLLBACK TO SAVEPOINT sp1; -- 回滾到 sp1,僅撤銷第二條 UPDATE
COMMIT; -- 提交第一條 UPDATE (張三扣款生效,李四未入賬 - 業務邏輯通常不這樣做,演示語法)
保存點用途:嵌套業務邏輯中,內層失敗需回滾到外層某個檢查點,而非整個事務回滾。
Connection con = dataSource.getConnection();
try {
con.setAutoCommit(false); // 關鍵:關閉自動提交
// 業務 SQL 1
// 業務 SQL 2
con.commit(); // 全部成功提交
} catch (SQLException e) {
try { con.rollback(); } catch (SQLException ex) { log.error("回滾失敗", ex); }
throw new RuntimeException("事務執行失敗", e);
} finally {
try { con.setAutoCommit(true); } catch (SQLException e) { log.warn("恢復自動提交失敗", e); }
close(con);
}
@Transactional(readOnly=true) 可提示優化器、避免不必要的鎖。REPEATABLE READ (防幻讀);高並發讀多寫少可考慮 READ COMMITTED + Binlog ROW 格式。--- 完 ---