批量启动流程接口 - 保证事务回滚

该接口用于批量启动流程,并通过提取方法和事务注解,确保循环过程中异常能够触发全部事务回滚,保证数据一致性。

原接口代码

@PostMapping('startProcessBatch')
public List<JsonResult> startProcessBatch(@ApiParam @RequestBody List<ProcessStartCmd> startCmdList) {
    List<JsonResult> result = new ArrayList<>();
    for (ProcessStartCmd startCmd : startCmdList) {
        JsonResult jsonResult = handReq(startCmd);
        if (!jsonResult.isSuccess()) {
            result.add(jsonResult);
            continue;
        }
        BpmDef bpmDef = (BpmDef) jsonResult.getData();
        boolean hasRight = systemClient.findAuthRight('BPM', 'def.start', bpmDef.getTreeId());
        if (!hasRight) {
            result.add(JsonResult.Fail('你没有启动权限!'));
            continue;
        }

        String operate = startCmd.isHasPk() ? ProcessStartCmd.OPERATE_LIVE : ProcessStartCmd.OPERATE_START;
        try {
            //启动流程
            BpmInst bpmInst = bpmInstService.doStartProcess(startCmd, bpmDef, operate);
            jsonResult.setDetailMsg(JSON.toJSON(startCmd.getVars()).toString());
            //发送任务消息通知
            messageService.sendMsg();
            result.add(jsonResult.setData(bpmInst)
                    .setSuccess(true).setMessage('成功启动流程!'));
        } catch (Exception e) {
            bpmInstService.handStartException(e);
            result.add(null);
        }
    }
    return result;
}

问题分析

由于该接口在循环体中执行了多个操作,如果在循环过程中发生异常,可能导致部分流程启动成功,而其他流程启动失败,数据不一致。

修改后的代码

为了保证在循环过程中报错会触发全部的事务回滚,可以将循环体内的代码块提取为一个独立的方法,并在该方法上添加事务注解。然后在循环体内调用该方法即可。

@PostMapping('startProcessBatch')
public List<JsonResult> startProcessBatch(@ApiParam @RequestBody List<ProcessStartCmd> startCmdList) {
    List<JsonResult> result = new ArrayList<>();
    for (ProcessStartCmd startCmd : startCmdList) {
        try {
            JsonResult jsonResult = startProcess(startCmd);
            result.add(jsonResult);
        } catch (Exception e) {
            result.add(null);
        }
    }
    return result;
}

@Transactional(rollbackFor = Exception.class)
public JsonResult startProcess(ProcessStartCmd startCmd) {
    JsonResult jsonResult = handReq(startCmd);
    if (!jsonResult.isSuccess()) {
        return jsonResult;
    }
    BpmDef bpmDef = (BpmDef) jsonResult.getData();
    boolean hasRight = systemClient.findAuthRight('BPM', 'def.start', bpmDef.getTreeId());
    if (!hasRight) {
        return JsonResult.Fail('你没有启动权限!');
    }

    String operate = startCmd.isHasPk() ? ProcessStartCmd.OPERATE_LIVE : ProcessStartCmd.OPERATE_START;
    try {
        //启动流程
        BpmInst bpmInst = bpmInstService.doStartProcess(startCmd, bpmDef, operate);
        jsonResult.setDetailMsg(JSON.toJSON(startCmd.getVars()).toString());
        //发送任务消息通知
        messageService.sendMsg();
        return jsonResult.setData(bpmInst)
                .setSuccess(true).setMessage('成功启动流程!');
    } catch (Exception e) {
        bpmInstService.handStartException(e);
        throw e;
    }
}

说明

  • @Transactional(rollbackFor = Exception.class) 注解用于指定方法为事务方法,并设置回滚异常类型为 Exception,表示任何异常都会触发回滚。
  • 通过将循环体内的代码提取为 startProcess 方法,并将事务注解应用于该方法,可以保证在循环过程中如果发生异常,将会触发全部的事务回滚。
  • startProcess 方法中,使用 throw e 将异常抛出,以便事务回滚机制能够正常工作。
批量启动流程接口 - 保证事务回滚

原文地址: https://www.cveoy.top/t/topic/qeqg 著作权归作者所有。请勿转载和采集!

免费AI点我,无需注册和登录