Hyperf 3.1 中 withTransaction 更安全简洁,自动处理提交与回滚,避免手写 try...finally 遗漏 rollback 或逻辑混乱,支持嵌套事务(保存点)及异常驱动回滚。

Hyperf 3.1 中 withTransaction 是一个更简洁、安全的事务封装方式,它自动处理提交与回滚,无需手动写 try...finally + $transaction->commit()/$transaction->rollback()。核心是把业务逻辑作为闭包传入,框架内部完成异常捕获和事务控制。
为什么要用 withTransaction 而不是手写 try finally
手写 try...finally 容易遗漏 rollback(比如在 finally 里没判断是否已提交),或在多层嵌套时逻辑混乱。withTransaction 保证:成功则自动 commit,抛出 Throwable(包括 Exception 和 Error)则自动 rollback,且支持嵌套事务(通过保存点)。
基本用法:替换简单 try finally
假设你原来这样写:
$transaction = $this->db->beginTransaction();
try {
$this->userDao->update(['status' => 1], ['id' => 1]);
$this->logDao->insert(['action' => 'user_updated']);
$transaction->commit();
} catch (\Throwable $e) {
$transaction->rollback();
throw $e;
}
现在可直接写成:
$this->db->withTransaction(function () {
$this->userDao->update(['status' => 1], ['id' => 1]);
$this->logDao->insert(['action' => 'user_updated']);
});
✅ 自动 commit
❌ 抛异常时自动 rollback 并重新抛出
⚠️ 注意:闭包内不要调用 $this->db->commit() 或 rollback(),会破坏机制
处理自定义回滚条件(不只是异常)
如果某些业务逻辑需要“主动回滚”(比如校验不通过但不抛异常),可用 throw new RuntimeException('need rollback'),或更推荐的方式是使用 Hyperf\Database\ConnectionInterface::transactionLevel() 判断当前是否在事务中,再手动 rollback —— 但通常建议统一用异常驱动,保持语义清晰。
- 推荐:用
throw new LogicException('xxx')触发回滚 - 避免:在闭包里调用
$this->db->rollback(),会导致后续操作出错 - 注意:闭包返回值会被原样返回,可用于传递结果,如:
return $user->id;
嵌套事务与保存点(savepoint)
Hyperf 3.1 的 withTransaction 支持嵌套。外层事务未提交前,内层调用会创建 savepoint;内层异常只回滚到该 savepoint,不影响外层。
$this->db->withTransaction(function () {
$this->orderDao->create([...]);
// 内层事务(实际是 savepoint)
$this->db->withTransaction(function () {
$this->paymentDao->create([...]);
if (rand(0,1)) {
throw new \RuntimeException('payment failed'); // 仅回滚 payment,order 仍有效
}
});
$this->notifyService->send('order_created');
});
✅ 默认开启 savepoint 支持(MySQL/PostgreSQL) ❌ SQLite 不支持 savepoint 嵌套,此时内层会退化为独立事务(需谨慎)











