[英]@Transactional on @Async methods in Spring
我有一个场景,我调用了三个@Transactional @Async
方法。 除了所有三种方法都有自己的事务上下文外,一切正常。 我想在调用方法的事务上下文中执行它们。
我的调用方法是这样的:
@Transactional
public void execute(BillingRequestDto requestDto) {
try {
LOGGER.info("Start Processing Request : {}", requestDto.getId());
List<Future<?>> futures = new ArrayList<>();
futures.add(inboundProcessingService.execute(requestDto));
futures.add(orderProcessingService.execute(requestDto));
futures.add(waybillProcessingService.execute(requestDto));
futures.stream().parallel().forEach(future -> {
try {
future.get();
} catch (Exception e) {
futures.forEach(future1 -> future1.cancel(true));
throw new FBMException(e);
}
});
requestDto.setStatus(RequestStatus.SUCCESS.name());
requestDto.setCompletedAt(new Date());
LOGGER.info("Done Processing Request : {}", requestDto.getId());
} catch (Exception e) {
requestDto.setStatus(RequestStatus.FAIL.name());
requestDto.setCompletedAt(new Date());
throw new FBMException(e);
}
}
并且所有被调用的方法都用@Async
和@Transactional
注释。
@Transactional
@Async
public Future<Void> execute(BillingRequestDto requestDto) {
LOGGER.info("Start Waybill Processing {}", requestDto.getId());
long count = waybillRepository.deleteByClientNameAndMonth(requestDto.getClientName(), requestDto.getMonth());
LOGGER.info("Deleted {} Records for Request {} ", count, requestDto.getId());
try (InputStream inputStream = loadCsvAsInputStream(requestDto)) {
startBilling(requestDto, inputStream);
} catch (IOException e) {
LOGGER.error("Error while processing");
throw new FBMException(e);
}
LOGGER.info("Done Waybill Processing {}", requestDto.getId());
return null;
}
所有三种方法的实现或多或少是相同的。
现在,如果这些方法中的任何一个出现故障,则仅回滚该方法的事务。
我的要求是在调用方法事务上下文中运行所有三种方法,因此一种方法中的任何异常都将回滚所有三种方法。
如果我禁用@Async
则此方案效果很好。 有一些方法需要时间,所以我希望它们并行运行。
请为此提出任何解决方案。
我想你应该使用 spring TransactionTemplate
进行编程控制。
主线程应该执行控制,如果任何线程抛出异常,您应该通知其他线程它们应该被回滚。
说,执行后的每个“事务性”线程都应该wait()
,在没有异常的情况下只执行notifyAll()
并在您的线程中执行事务提交,如果出现异常,您应该调用Thread.interrupt()
并进行回滚。
我认为你的@Async
方法可以抛出已检查的异常
@Transactional
@Async
public Future<Void> execute(BillingRequestDto requestDto) throw RollBackParentTransactionException {
...
}
并且调用者可以注释为:
@Transactional(rollbackFor = RollBackParentTransactionException.class)
public void execute(BillingRequestDto requestDto) { ... }
那应该工作。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.