db::transaction()是thinkphp6.x保障多表操作一致性的核心手段,需确保同一连接、显式处理异常、强制主库执行、依赖innodb引擎及数据库约束。

ThinkPHP6.x 中,Db::transaction() 是保障多表操作一致性的核心手段。它不是简单地“包住几条 SQL”,而是通过底层事务机制确保所有写入要么全部生效、要么全部撤销——前提是操作都在同一数据库连接中,且异常被正确处理。
闭包式事务最稳妥
推荐优先使用闭包方式启动事务,代码简洁、逻辑集中:
- 事务自动开启,闭包执行完毕无异常则自动提交
- 闭包内任意位置抛出异常(包括模型 save、validate 失败、自定义 throw),都不会提交
- 但注意:TP6 默认不会自动回滚非 PDO 异常,比如文件读取失败、HTTP 调用超时等,必须显式捕获并处理
多表操作必须包裹在同一个事务内
比如订单创建 + 库存扣减 + 日志记录,三者缺一不可:
- 中间表操作(如用户-角色关联)也必须包含在事务中,否则可能写入一半就中断
- 若用了 belongsToMany 关联且中间表含业务字段(如 status、sort),需配合中间模型 + through,但数据写入仍要由事务兜底
- 跨模型操作(User::create()、Order::create())只要共用默认数据库连接,就天然处于同一事务上下文
读写分离环境下要强制走主库
如果开启了读写分离,事务期间的查询和写入都必须落在主库,否则会出现“查不到刚写的记录”或“事务失效”:
- 配置
'read_master' => true可让事务内所有 Db 操作自动切到主库 - 或手动指定:
Db::connect('mysql')->transaction(...) - 避免在事务中调用
Db::name()->select()后又做判断再写入——该 select 若走了从库,结果可能滞后
别忽略数据库引擎和字段约束
事务只是应用层兜底,基础保障还得靠数据库本身:
- 确保表引擎为 InnoDB,MyISAM 不支持事务
- 关键字段加唯一索引(如订单号)、外键约束(如 user_id 必须存在),能拦截大部分脏数据
- where 条件注意区分
IS NULL和= '',否则可能误删/漏更新 - 大表校验类场景(如对账)不依赖事务,而应改用 SQL 聚合函数 + 指纹比对(如
md5(serialize()))
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











