PHP用PDO时关自动提交应调用beginTransaction(),它自动关闭autocommit且兼容性好;若用setAttribute(PDO::ATTR_AUTOCOMMIT, false)需确保后续调用beginTransaction(),否则commit会报错“无活跃事务”。

phpEnv 环境下事务不自动提交,核心不是改 phpEnv 配置,而是控制数据库连接本身的 autocommit 行为——PDO 默认开启自动提交,必须显式关闭才能手动控制 commit/rollback。
PHP 用 PDO 时怎么关自动提交
PDO 连接创建后,默认 PDO::ATTR_AUTOCOMMIT 是 true。不能靠 phpEnv 的 Apache 或 PHP 全局配置关掉它,得在代码里设:
- 调用
$pdo->setAttribute(PDO::ATTR_AUTOCOMMIT, false)——但注意:这仅在未开启事务前有效;一旦调用了beginTransaction(),PDO 会自动关 autocommit,此时再设这个属性无效 - 更稳妥的做法是直接调
$pdo->beginTransaction(),它内部会确保 autocommit 关闭,且兼容性更好(MySQLi 不支持该方法) - 若已用
setAttribute关了 autocommit,后续又没调beginTransaction(),那所有 SQL 仍处于“无事务上下文”的非自动提交状态,容易误判——此时commit()会报错 “There is no active transaction”
MySQLi 下禁用自动提交的正确写法
MySQLi 不提供 beginTransaction() 的封装,必须手动管理 autocommit 开关:
- 先执行
mysqli_autocommit($conn, false),返回 true 才表示成功关闭 - 执行完所有 SQL 后,用
mysqli_commit($conn)提交,或mysqli_rollback($conn)回滚 - 关键点:事务结束后必须手动恢复
mysqli_autocommit($conn, true),否则后续所有查询都卡在非自动提交状态,新请求可能莫名失败 - 如果忘了恢复,且连接被复用(如长连接池),问题会蔓延到其他请求
为什么在 phpMyAdmin 里 SET autocommit=0 没用
phpEnv 套件通常自带 phpMyAdmin,但它的 SQL 窗口默认每条语句独立执行、会话不延续。直接输 SET autocommit = 0 看似生效,但下一条语句(比如 UPDATE)可能已在新会话中运行,autocommit 又回到 1:
- 验证方式:执行
SELECT @@autocommit,看是否真为 0 - 可靠做法是用
START TRANSACTION显式开事务,然后在同一窗口连续执行 SQL、COMMIT或ROLLBACK - phpMyAdmin 的“SQL”页顶部有「启用自动提交」开关,勾掉它比手输
SET更稳——但仅对当前标签页有效 - 表引擎必须是
InnoDB,MyISAM表上任何事务控制都无效,SHOW TABLE STATUS LIKE 'table_name'可确认
最容易被忽略的三个细节
事务不是开了就安全,以下三点出错会导致数据不一致却无报错:
-
PDO::ERRMODE_EXCEPTION必须提前设好,否则 SQL 错误不会抛异常,catch块捕不到,rollback()就永远不会执行 - 事务中混用 PDO 和 MySQLi 连接,或跨多个
$pdo实例操作同一库,它们互不可见——事务只在单个连接内有效 - 长时间未提交的事务(比如卡在业务逻辑里 sleep(30)),可能被 MySQL 的
wait_timeout或innodb_lock_wait_timeout中断,连接断开时 PDO 自动 rollback,但 PHP 层未必感知到
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











