You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Laravel分步提交场景下如何实现全事务回滚?

Laravel分步操作全事务回滚解决方案

你的核心问题是分步提交的事务无法全局回滚,本质原因是每步单独提交的事务已经持久化到数据库,无法直接回滚。针对单请求和跨请求两种场景,分别给出可行方案:

场景1:单请求内分步处理

如果所有分步操作在同一个请求内完成(比如前端单页分步展示,后端一次请求处理全流程),直接用Laravel全局事务包裹所有步骤即可:

public function multiStepStore(Request $request)
{
    DB::beginTransaction();
    
    try {
        // 第一步操作
        $this->storeStep1($request);
        // 返回第一步完成提示(前端可根据此更新界面)
        echo json_encode(['message' => '第一步完成']);
        
        // 第二步操作
        $this->storeStep2($request);
        echo json_encode(['message' => '第二步完成']);
        
        // 所有步骤完成后提交事务
        DB::commit();
        return response()->json(['message' => '所有操作完成']);
    } catch (\Exception $e) {
        // 任意步骤出错,全量回滚
        DB::rollBack();
        return response()->json(['error' => $e->getMessage()], 500);
    }
}

场景2:跨请求分步处理(HTTP无状态场景)

如果是多请求分步提交(比如每步单独发请求),HTTP无状态导致无法保持长事务,改用临时存储+最终提交方案:

步骤1:初始化批次ID并存储临时数据

public function step1(Request $request)
{
    $batchId = Str::uuid()->toString();
    session(['batch_id' => $batchId]);
    
    try {
        // 存储时标记为临时数据,关联批次ID
        UserInfo::create([
            'name' => $request->name,
            'is_temp' => true,
            'batch_id' => $batchId
        ]);
        
        return response()->json(['message' => '第一步完成']);
    } catch (\Exception $e) {
        // 出错则清理当前批次临时数据
        UserInfo::where('batch_id', $batchId)->delete();
        session()->forget('batch_id');
        return response()->json(['error' => $e->getMessage()], 500);
    }
}

步骤2:继续存储临时数据

public function step2(Request $request)
{
    $batchId = session('batch_id');
    if (!$batchId) {
        return response()->json(['error' => '请先完成第一步'], 400);
    }
    
    try {
        Order::create([
            'goods_id' => $request->goods_id,
            'is_temp' => true,
            'batch_id' => $batchId
        ]);
        
        return response()->json(['message' => '第二步完成']);
    } catch (\Exception $e) {
        // 出错清理当前批次所有临时数据
        UserInfo::where('batch_id', $batchId)->delete();
        Order::where('batch_id', $batchId)->delete();
        session()->forget('batch_id');
        return response()->json(['error' => $e->getMessage()], 500);
    }
}

步骤3:最终提交,转正临时数据

public function finish()
{
    $batchId = session('batch_id');
    if (!$batchId) {
        return response()->json(['error' => '请完成所有步骤'], 400);
    }
    
    DB::beginTransaction();
    try {
        // 将临时数据转为正式数据
        UserInfo::where('batch_id', $batchId)->update(['is_temp' => false]);
        Order::where('batch_id', $batchId)->update(['is_temp' => false]);
        
        DB::commit();
        session()->forget('batch_id');
        return response()->json(['message' => '所有操作完成,数据已正式保存']);
    } catch (\Exception $e) {
        DB::rollBack();
        // 提交失败仍清理临时数据
        UserInfo::where('batch_id', $batchId)->delete();
        Order::where('batch_id', $batchId)->delete();
        session()->forget('batch_id');
        return response()->json(['error' => $e->getMessage()], 500);
    }
}

额外优化

  • 给临时数据加过期时间,定时清理未提交的垃圾数据;
  • 用Redis替代Session存储批次ID,适配分布式部署场景。

内容的提问来源于stack exchange,提问作者vinod

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 10:55:09