首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫

MySQL 事務機制深度解析:ACID 特性、隔離級別與 PHP 實戰

     編輯:MySQL 資料庫相關知識

事務核心概念

事務是一組不可分割的 SQL 操作序列,滿足 ACID 四大特性:

特性全稱含義MySQL 實現
AAtomicity原子性:全做或全不做Undo Log 回滾
CConsistency一致性:資料庫從一個一致狀態轉移到另一個約束、觸發器、外鍵
IIsolation隔離性:並發事務互不干擾鎖、MVCC
DDurability持久性:提交後永久生效Redo Log、雙重寫緩衝

支援事務的儲存引擎

  • InnoDB:預設、完整支援 ACID、行鎖、MVCC、外鍵
  • NDB Cluster:分散式、支援事務
  • MyISAM / MEMORY / CSV:不支援 事務

建表必須指定:ENGINE=InnoDB

四大隔離級別與現象對比

設定隔離級別

-- 當前會話
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;

-- 全域永久
SET GLOBAL TRANSACTION ISOLATION LEVEL READ COMMITTED;
-- 或 my.cnf
[mysqld]
transaction-isolation = READ-COMMITTED

不可回滾的語句(隱性提交)

以下語句會導致隱性提交,結束當前事務,無法回滾:

  • DDL:CREATE/DROP/ALTER DATABASE/TABLE/VIEW/INDEX
  • 資料庫管理:TRUNCATE TABLE、LOCK TABLES、UNLOCK TABLES
  • 複制/備份:START REPLICA、STOP REPLICA、RESET MASTER
  • 帳號管理:CREATE/DROP/ALTER USER、GRANT/REVOKE
  • 其他:ANALYZE TABLE、CHECK TABLE、OPTIMIZE TABLE、REPAIR TABLE

鐵律:事務中嚴禁混用 DDL 與 DML。

PHP 實戰:mysqli 事務控制

connect_errno) {
    die("Connect failed: " . $mysqli->connect_error);
}

try {
    // 關閉自動提交
    $mysqli->autocommit(false);
    
    // 業務邏輯:新增員工 + 電話
    $sql1 = "INSERT INTO employee (first_name, last_name, job_title, salary) 
             VALUES ('Grace', 'Williams', 'Software Engineer', 5000)";
    if (!$mysqli->query($sql1)) {
        throw new Exception("Employee insert failed: " . $mysqli->error);
    }
    $emp_id = $mysqli->insert_id;  // 取得自增 ID
    
    $sql2 = "INSERT INTO telephone (employee_id, type, no) 
             VALUES ($emp_id, 'mobile', '270-598712')";
    if (!$mysqli->query($sql2)) {
        throw new Exception("Phone insert failed: " . $mysqli->error);
    }
    
    // 全部成功 → 提交
    $mysqli->commit();
    echo "Transaction committed successfully.";
    
} catch (Exception $e) {
    // 任何失敗 → 回滾
    $mysqli->rollback();
    echo "Transaction rolled back: " . $e->getMessage();
} finally {
    $mysqli->autocommit(true);  // 恢復自動提交
    $mysqli->close();
}
?>

關鍵點解析

  1. autocommit(false):關鍵步驟,否則每條 SQL 即時提交
  2. insert_id:在事務中也能正確取得自增 ID
  3. try-catch:確保異常路徑也能回滾
  4. finally:恢復連線預設行為,避免連線池污染

PDO 版本(推薦現代專案)

 PDO::ERRMODE_EXCEPTION,
    PDO::ATTR_EMULATE_PREPARES => false,
]);

try {
    $pdo->beginTransaction();
    
    $stmt = $pdo->prepare("INSERT INTO employee (first_name, last_name, job_title, salary) VALUES (?, ?, ?, ?)");
    $stmt->execute(['Grace', 'Williams', 'Software Engineer', 5000]);
    $emp_id = $pdo->lastInsertId();
    
    $stmt = $pdo->prepare("INSERT INTO telephone (employee_id, type, no) VALUES (?, ?, ?)");
    $stmt->execute([$emp_id, 'mobile', '270-598712']);
    
    $pdo->commit();
    echo "Success";
} catch (Exception $e) {
    $pdo->rollBack();
    echo "Failed: " . $e->getMessage();
}
?>

事務效能優化建議

  1. 縮短事務範圍:只包含必要的寫操作,讀操作移至事務外
  2. 避免長事務:長事務持有鎖久、阻塞其他事務、Undo Log 膨脹
  3. 合理索引:減少掃描行數,縮短鎖持有時間
  4. 批次提交:大量寫入分批,每批 100-1000 行提交一次
  5. 監控指標:Innodb_row_lock_waits、Innodb_row_lock_time_avg、Trx_rseg_history_len

死鎖處理

  • InnoDB 自動偵測並回滾代價較小的事務(返回 ERROR 1213)
  • 應用層捕獲 1213 錯誤後重試(指數退避)
  • 固定加鎖順序(如:按主鍵遞增順序更新多表)
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
隔離級別髒讀不可重複讀幻讀MySQL 預設
READ UNCOMMITTED✅ 可能✅ 可能✅ 可能否
READ COMMITTED❌ 不可能✅ 可能✅ 可能否(推薦生產)
REPEATABLE READ❌ 不可能❌ 不可能✅ 可能(間隙鎖緩解)✅ 是
SERIALIZABLE❌ 不可能❌ 不可能❌ 不可能否(效能極差)