必须将整个操作包裹在db::transaction()中:第一步用闭包封装全部逻辑,第二步在闭包内依次查父记录、查子集、更新子集,第三步确保所有操作使用同一连接且不在闭包外调用save/update。

在Laravel中执行多层嵌套查询并确保数据一致性时,必须将整个操作包裹在数据库事务中,否则中间某一步失败会导致部分写入、状态不一致。直接用DB::transaction()包裹嵌套逻辑是最稳妥的方式,避免手动调用commit/rollback出错。
基础嵌套查询+事务封装
第一步:用 DB::transaction() 包裹整个业务逻辑块,Laravel会在异常抛出时自动回滚。
第二步:在闭包内依次执行子查询——先查父记录,再用其ID查子集,最后更新子集状态。
第三步:所有查询都使用 DB::table() 或 Eloquent 模型,但必须确保它们共享同一连接实例(默认即满足)。
这一步操作起来很简单,直接把文件拖进去就行。注意:不能在事务闭包外对查询结果做 save() 或 update(),否则会脱离事务上下文。
带条件判断的嵌套事务(含 rollbackIf)
方法一:使用 DB::transaction() + 手动检查 + throw new Exception()
查询订单主表 → 根据订单状态决定是否继续 → 查询关联发货单 → 若发货单已存在则抛出异常终止事务 → 否则插入新发货单。
方法二:用 DB::transaction() 的第二个参数指定重试次数,适用于并发冲突场景,但对业务逻辑判断无效。
【必须在抛异常前完成所有数据库操作,否则 rollback 无法清理已执行的语句】
Laravel 10+ 中使用 query builder 嵌套 with() 的事务写法
① 先用 DB::transaction() 开启事务;
② 使用 DB::table('orders')->where('id', $id)->with(['items', 'customer'])->first() 获取带关联的主记录;
③ 对 items 集合遍历执行 DB::table('items')->where('order_id', $id)->update(['processed' => true]);
④ 最后调用 DB::table('orders')->where('id', $id)->update(['status' => 'done']);
注意:with() 在事务中可用,但仅限于 select,不能用于 insert/update 的嵌套链式调用;Eloquent 的 save() 和 update() 在事务内自动绑定连接。











