保证子线程中事务的一致性

0 前沿

逻辑如下:
① 主线程新增数据库表A记录,状态为新增中
② 子线程去读txt中的数据,读取失败,更新表A的状态为失败;读取成功:1)更新表A状态为成功;2)将txt数据新增到表B;3)新增基础信息到表C

1 代码

XXXImpl:

@Resource
private DataMapper dataMapper;

@Resource
private DataAsyncService dataAsyncService;

String fileName = file.getOriginalFilename();
 // 新增标准格式记录
 dataMapper.addRecord(importModel);
 // 异步读取文件中的数据
 ExecutorService executor = Executors.newCachedThreadPool();
 executor.submit(() -> {
     try {
         dataAsyncService.asyncAddDataHandle(model, file, fileName, importModel);
     } catch (Exception e) {
         dataMapper.updateRecord(importModel.getId(), ImportStatus.FAIL.getCode(), null);
         log.error("文件读取失败:{}", e.getMessage());
         Thread.currentThread().interrupt();
     } finally {
         executor.shutdownNow();
     }
 });
 return AjaxResult.success();

DataAsyncServiceImpl:

@Transactional
public void asyncAddDataHandle() {
  try {
      // 附件读取
      DataResult dataResult = FileReadUtils.readData(file);
      // 新增基础数据
      dataMapper.addBase(model);
      // 更新记录
      dataMapper.updateRecord(importModel.getId(), ImportStatus.SUCCESS.getCode(), fileModel.getFilePath());
      // 新增txt数据
      dataMapper.addFileData(models);
  } catch (Exception e) {
      throw new BusinessException(e.getMessage());
  }
}

2 说明

1)DataAsyncServiceImpl中的asyncAddDataHandle方法如果写到XXXImpl会回滚不了,原因:
① 事务注解生效条件:@Transactional注解的方法必须是public,且由 Spring 容器管理(不能是 private/protected,不能在同类中直接调用,需通过 Bean 注入调用)。
② 异常处理:异步方法中需捕获异常并重新抛出,否则 Spring 无法感知异常,事务不会回滚。
2)或者可以尝试在XXXImpl中注入自身,然后把asyncAddDataHandle方法写在XXXImpl中
3)也可以使用 Spring 的@Async替代手动创建线程池,没尝试
4)如若此方法存在其他问题,麻烦在评论区中给出

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值