不是必须,但多条写操作需原子性时必须显式开启事务;PDO默认自动提交,须先关闭自动提交、再beginTransaction()、最后commit()/rollback(),三步缺一不可。

PHP PDO 连 MySQL 时事务是否必须用 beginTransaction()?
不是“必须”,但凡涉及多条写操作且需保证原子性(比如转账、库存扣减+订单生成),就必须显式开启事务。PDO 默认是自动提交模式(ATTR_AUTOCOMMIT 为 true),单条 INSERT/UPDATE 执行完立刻生效,不加事务控制就谈不上回滚。
开启事务的三个关键步骤和常见翻车点
实际写法很简单,但三步缺一不可,漏掉任意一个都会让事务失效:
- 关闭自动提交:
$pdo->setAttribute(PDO::ATTR_AUTOCOMMIT, false)—— 不设这句,beginTransaction()可能静默失败或被忽略 - 显式开始事务:
$pdo->beginTransaction()—— 必须在所有 SQL 执行前调用,不能写在try块中间 - 手动提交或回滚:
$pdo->commit()或$pdo->rollback()—— 不能依赖脚本结束自动释放,PHP 进程退出不会帮你回滚未完成事务
示例片段:
$pdo->setAttribute(PDO::ATTR_AUTOCOMMIT, false);
try {
$pdo->beginTransaction();
$pdo->exec("UPDATE accounts SET balance = balance - 100 WHERE id = 1");
$pdo->exec("UPDATE accounts SET balance = balance + 100 WHERE id = 2");
$pdo->commit();
} catch (Exception $e) {
$pdo->rollback();
throw $e;
}
为什么 rollback() 有时不生效?
最常见原因是 MySQL 存储引擎不支持事务。InnoDB 支持,MyISAM 不支持 —— 即使你写了 beginTransaction() 和 rollback(),MyISAM 表上的修改依然已提交,回滚完全无效。检查方式:SHOW CREATE TABLE your_table,看输出里是 ENGINE=InnoDB 还是 ENGINE=MyISAM。
立即学习“PHP免费学习笔记(深入)”;
其他原因包括:
- 事务过程中执行了 DDL 语句(如
CREATE TABLE、ALTER TABLE),MySQL 会自动提交当前事务 - 连接被意外中断(如超时、网络断开),而代码没捕获到异常,导致没走到
rollback() - 用了
PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => true以外的流式查询,某些驱动下事务状态可能不同步
嵌套事务和保存点在 PDO 中怎么处理?
PDO 本身不提供原生嵌套事务 API,MySQL 也不真正支持嵌套事务(SAVEPOINT 是替代方案)。如果你需要局部回滚,得手动用 SAVEPOINT:
$pdo->exec("SAVEPOINT sp1");
// ... 中间出错
$pdo->exec("ROLLBACK TO SAVEPOINT sp1");注意:SAVEPOINT 名字要唯一,且不能跨连接复用;RELEASE SAVEPOINT 不常用,一般靠最后 COMMIT 自动清理。
真正复杂的业务逻辑(比如微服务间协调)别硬靠数据库事务兜底,PDO 事务只适合单库、单连接、短生命周期的操作。











