如何优雅使用ThinkPHP基于闭包实现数据库事务处理?
- 内容介绍
- 文章标签
- 相关推荐
本文共计1003个文字,预计阅读时间需要5分钟。
由于闭包内异常会自动回滚,因此不需要手动编写`try/catch`和`rollback()`。避免遗漏或误判,手动方式一旦忘记记录捕获的异常(如模型事件中抛出的异常),事务就会卡在开启状态。后续请求可能会尝试锁定已被事务锁定的表。
常见错误现象:SQLSTATE[HY000]: General error: 1205 Deadlock found when trying to get lock 或长时间未提交的事务占用连接。
- 闭包方式会在退出时自动判断:有未捕获异常 →
rollback();无异常 →commit() - 闭包内所有数据库操作共享同一个 PDO 连接和事务上下文,包括
Model::save()、Db::table()->insert()等 - 不支持嵌套闭包事务(外层
Db::transaction()内再调Db::transaction()),会报Transaction already started
Db::transaction() 里调用模型方法要注意什么
ThinkPHP 模型默认使用独立数据库连接实例,直接在闭包里调 UserModel::create() 可能脱离当前事务——除非你确认该模型没改过 $connection 配置,且没启用 use_transaction 以外的连接策略。
使用场景:需要同时更新用户主表 + 关联的 profile 表 + 日志记录,三者必须原子性。
本文共计1003个文字,预计阅读时间需要5分钟。
由于闭包内异常会自动回滚,因此不需要手动编写`try/catch`和`rollback()`。避免遗漏或误判,手动方式一旦忘记记录捕获的异常(如模型事件中抛出的异常),事务就会卡在开启状态。后续请求可能会尝试锁定已被事务锁定的表。
常见错误现象:SQLSTATE[HY000]: General error: 1205 Deadlock found when trying to get lock 或长时间未提交的事务占用连接。
- 闭包方式会在退出时自动判断:有未捕获异常 →
rollback();无异常 →commit() - 闭包内所有数据库操作共享同一个 PDO 连接和事务上下文,包括
Model::save()、Db::table()->insert()等 - 不支持嵌套闭包事务(外层
Db::transaction()内再调Db::transaction()),会报Transaction already started
Db::transaction() 里调用模型方法要注意什么
ThinkPHP 模型默认使用独立数据库连接实例,直接在闭包里调 UserModel::create() 可能脱离当前事务——除非你确认该模型没改过 $connection 配置,且没启用 use_transaction 以外的连接策略。
使用场景:需要同时更新用户主表 + 关联的 profile 表 + 日志记录,三者必须原子性。

