必须调用mysqli::autocommit(false),否则begin_transaction()无效;因其仅发送START TRANSACTION命令而不改变autocommit状态,若未关闭自动提交,后续DML语句仍会立即提交,导致事务失效。

必须调用 mysqli::autocommit(false),否则 begin_transaction() 不起作用 —— 这是 PHP7.0+ 里最容易被忽略的前提。
为什么 begin_transaction() 不能自动关 autocommit
PHP 7.0 引入了 mysqli::begin_transaction(),但它只是发一条 START TRANSACTION 命令,并不修改连接的 autocommit 状态。如果 autocommit 仍为 true,那后续 SQL 依然会立即提交,事务形同虚设。
常见错误现象:执行了 $mysqli->begin_transaction(),也执行了 UPDATE 和 INSERT,最后 $mysqli->commit() 返回 true,但数据早就写进去了 —— 因为 autocommit 没关,每条语句都自己提交了。
- 务必在
begin_transaction()前调用$mysqli->autocommit(false) - 检查是否成功:调用后可查
$mysqli->options(MYSQLI_OPT_CONNECT_TIMEOUT, 10)无用,正确方式是执行SELECT @@autocommit确认返回值为 0 - 如果用的是长连接或连接池,autocommit 状态可能被上一个请求残留影响,每次事务前都应显式重置
autocommit(false) 后要不要手动 START TRANSACTION
不需要。调用 $mysqli->autocommit(false) 后,任何 DML(INSERT/UPDATE/DELETE)都进入“待提交”状态;begin_transaction() 只是加一层语义保障和兼容性封装,不是必需步骤。
立即学习“PHP免费学习笔记(深入)”;
但推荐保留它:一是明确表达事务意图,二是避免某些旧版 MySQL 客户端驱动对纯 autocommit=0 模式支持不一致。
- 安全写法顺序:
$mysqli->autocommit(false)→$mysqli->begin_transaction() - 若跳过
begin_transaction(),直接执行 DML +commit(),也能工作,但出错时rollback()可能不触发(取决于 MySQL 版本和协议层行为) - 注意:
begin_transaction()在 PHP 7.0+ 才可用;低于该版本只能靠query("START TRANSACTION")或autocommit(false)单独控制
事务结束后必须恢复 autocommit 吗
必须。autocommit 是连接级状态,不恢复会导致后续所有独立查询都滞留在未提交状态,轻则数据看不见,重则锁表、连接卡死。
典型坑:事务中途异常退出,没走到 $mysqli->autocommit(true),下一次请求复用这个连接,连 SELECT 都可能被阻塞(尤其 InnoDB 行锁未释放)。
- 标准收尾三步:成功时
commit()→autocommit(true);失败时rollback()→autocommit(true) - 别依赖脚本结束自动恢复 —— mysqli 连接可能被复用(如使用 pconnect 或连接池)
- 可在 try/catch finally 中统一处理:
finally { $mysqli->autocommit(true); },但要注意autocommit(true)本身也可能失败(网络中断等),需容忍
真正麻烦的不是怎么关,而是关了之后忘了开 —— 大多数线上事务问题,根源都在这里。



















