事務是關聯式資料庫可靠性的基石。本文從 InnoDB 架構視角切入,系統講解 ACID 實現、四大隔離級別與鎖關係、PHP mysqli 事務模板、以及 DDL 隱性提交 等實戰陷阱。
CREATE TABLE employee (...) ENGINE=InnoDB;
CREATE TABLE telephone (...) ENGINE=InnoDB;
MyISAM、MEMORY 等引擎不支援事務,操作即時生效,無回滾能力。
| 特性 | InnoDB 實現機制 |
|---|---|
| Atomicity (原子性) | Undo Log 記錄反向操作,Crash Recovery 時回滾未提交事務 |
| Consistency (一致性) | Foreign Key、Check Constraint、Trigger + 原子性保證 |
| Isolation (隔離性) | MVCC + Row Lock + Gap Lock + Next-Key Lock |
| Durability (持久性) | Redo Log (WAL) + Doublewrite Buffer + innodb_flush_log_at_trx_commit=1 |
| 隔離級別 | 髒讀 | 不可重複讀 | 幻讀 | InnoDB 鎖策略 |
|---|---|---|---|---|
| READ UNCOMMITTED | ✅ | ✅ | ✅ | 無鎖,極少用 |
| READ COMMITTED | ❌ | ✅ | ✅ | 行鎖,無 Gap Lock |
| REPEATABLE READ (預設) | ❌ | ❌ | ❌* | Next-Key Lock 防幻讀 |
| SERIALIZABLE | ❌ | ❌ | ❌ | 表鎖/全範圍鎖,併發極低 |
* RR 級別下 InnoDB 透過 Next-Key Lock 實質上解決了幻讀,但純 MVCC 快照讀仍可能見到幻影,需 SELECT ... FOR UPDATE 或 LOCK IN SHARE MODE 加鎖讀。
<?php
$mysqli = new mysqli('localhost', 'app', '****', 'biz_db');
$mysqli->autocommit(false); // 關閉自動提交
$ok = true;
try {
// 業務邏輯 1
$stmt = $mysqli->prepare("INSERT INTO employee (first_name,last_name,job_title,salary) VALUES (?,?,?,?)");
$stmt->bind_param('sssd', 'Grace', 'Williams', 'Software Engineer', 5000);
if (!$stmt->execute()) throw new Exception($stmt->error);
$emp_id = $mysqli->insert_id; // 取得自增 ID
// 業務邏輯 2 (依賴上一步 ID)
$stmt = $mysqli->prepare("INSERT INTO telephone (employee_id, type, no) VALUES (?,?,?)");
$stmt->bind_param('iss', $emp_id, 'mobile', '270-598712');
if (!$stmt->execute()) throw new Exception($stmt->error);
$mysqli->commit();
echo "Transaction committed. New employee ID: $emp_id";
} catch (Exception $e) {
$mysqli->rollback();
error_log("TX rollback: " . $e->getMessage());
http_response_code(500);
echo "Operation failed, rolled back.";
} finally {
$mysqli->autocommit(true); // 還原
$mysqli->close();
}
rollback() 執行。mysqli_errno=1213,指數退避重試 3 次。$mysqli->query("SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED");以下語句會隱性提交當前事務,導致前面操作無法回滾:
CREATE/ALTER/DROP TABLE, CREATE/DROP INDEX, TRUNCATE TABLECREATE/DROP DATABASE, RENAME TABLELOCK TABLES, UNLOCK TABLESLOAD DATA INFILE, LOAD XMLSTART/STOP REPLICA, CHANGE REPLICATION SOURCEGRANT/REVOKE, SET PASSWORD鐵律:事務中絕不執行 DDL。需變更結構請另開 Session、維護窗口或用 pt-online-schema-change。
-- 查看當前隔離級別
SELECT @@transaction_isolation;
-- 查看活躍事務
SELECT * FROM information_schema.INNODB_TRX\G
-- 查看鎖等待
SELECT * FROM information_schema.INNODB_LOCK_WAITS\G
結語:事務不是萬能藥,濫用長事務是資料庫殺手。理解 InnoDB MVCC 與鎖機制、避開隱性提交陷阱、編寫「短小精悍、異常必滾、死鎖重試」的事務程式碼,才能在高併發下守住資料一致性防線。