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)如若此方法存在其他问题,麻烦在评论区中给出