PHP中手动提交事务必须先调用beginTransaction()或autocommit(false)关闭自动提交,否则commit()静默失败;PDO推荐用beginTransaction()自动关自动提交,MySQLi需分两步设置;commit()后不自动恢复自动提交模式。

PHP中手动提交事务必须先开启事务
MySQLi 或 PDO 默认都是自动提交模式,commit() 不会起作用,除非你明确关闭了自动提交。不调用 begin_transaction()(PDO)或 autocommit(false)(MySQLi),后续所有 commit() 都是静默失败——没有报错,但数据也没真正提交。
- PDO 推荐用
$pdo->beginTransaction()开启,它会自动关掉自动提交 - MySQLi 要分两步:
$mysqli->autocommit(false)+ 手动$mysqli->query('START TRANSACTION')(后者非必须,但显式更安全) - 开启后,所有后续查询都在同一事务上下文中,直到
commit()或rollback()
commit() 失败的常见原因不是语法错误而是状态异常
commit() 返回 false 通常不是因为你写错了函数名,而是事务已处于不可提交状态:比如连接断开、超时、被其他线程 kill、或者之前执行过无法回滚的操作(如 CREATE TABLE、ALTER TABLE 在某些存储引擎下会隐式提交)。
- 检查返回值:
if (!$pdo->commit()) { /* 失败处理 */ },但更要查$pdo->errorInfo() - 避免在事务中混用 MyISAM 表(不支持事务)和 InnoDB 表,MyISAM 操作会触发隐式提交
- 长时间未提交的事务可能被 MySQL 的
wait_timeout或innodb_lock_wait_timeout终止,commit()会报MySQL server has gone away或锁等待超时
PDO commit() 后连接仍保持,但事务状态已结束
调用 $pdo->commit() 成功后,事务结束,自动提交模式**不会自动恢复**——PDO 仍处于手动事务模式,下次查询仍是“无事务包裹”的普通语句,但如果你紧接着又调 beginTransaction(),它才重新开始一个新事务。
- 不要假设
commit()之后自动回到 auto-commit 状态;如需恢复,得手动$pdo->setAttribute(PDO::ATTR_AUTOCOMMIT, true) - 如果忘记
commit()或rollback()就释放了 PDO 对象,PHP 结束时会尝试隐式回滚,但不可靠,尤其在长连接池(如 PHP-FPM 持久连接)中容易残留未结束事务 - 建议用 try/finally 包裹:开启事务 → 执行业务 → 成功则
commit(),异常则rollback(),finally 中确保清理(如重置 autocommit)
MySQLi 的 commit() 必须用 mysqli_real_connect() 初始化的连接
用 mysqli_connect() 创建的面向对象实例,$mysqli->commit() 是有效的;但若你用了过程式风格的 mysqli_connect() 返回的 resource,在 PHP 8.1+ 中已废弃,且其 mysqli_commit($link) 函数要求 $link 必须由 mysqli_real_connect() 显式建立(尤其是开启了 MYSQLI_CLIENT_FOUND_ROWS 等标志时)。
立即学习“PHP免费学习笔记(深入)”;
- 推荐统一使用面向对象风格:
$mysqli = new mysqli(...),再调$mysqli->commit() - 过程式调用
mysqli_commit()前,务必确认$link是有效且未关闭的连接资源 - MySQLi 的
commit()不抛异常,只返回 bool,需主动判断;而 PDO 可设PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION让失败直接 throw
事务真正生效的关键不在 commit() 这一行代码,而在它之前是否干净地隔离了上下文、是否规避了隐式提交操作、以及连接生命周期是否可控。漏掉其中任一环,都可能导致你以为提交了,其实什么都没发生。



















