【问题标题】:@Transactional on @Async methods in SpringSpring中@Async方法的@Transactional
【发布时间】:2018-02-26 11:39:37
【问题描述】:

我有一个调用三个@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,这种情况会很好。有一些耗时的方法,所以我希望它们并行运行。

请为此提出任何解决方案。

【问题讨论】:

  • @Async 方法在单独的线程中执行,因此不能使用调用者的同一个事务。

标签: java spring asynchronous transactions


【解决方案1】:

我认为你的@Async 方法可以抛出检查异常

@Transactional
@Async
public Future<Void> execute(BillingRequestDto requestDto) throw RollBackParentTransactionException {
...
}

并且调用者可以被注释:

@Transactional(rollbackFor = RollBackParentTransactionException.class)
public void execute(BillingRequestDto requestDto) { ... }

应该可以的。

【讨论】:

    【解决方案2】:

    我猜你应该使用 spring TransactionTemplate 进行程序控制。
    主线程应该执行控制,如果任何线程抛出异常,您应该通知其他线程应该回滚。

    说,执行后的每个“事务”线程应该wait(),在没有异常的情况下只执行notifyAll()并在你的线程中进行事务提交,如果出现异常你应该调用Thread.interrupt()并进行回滚。

    【讨论】:

      猜你喜欢
      • 2016-10-10
      • 2023-03-10
      • 2018-11-09
      • 2015-05-29
      • 2020-08-21
      • 1970-01-01
      • 2017-06-18
      • 1970-01-01
      • 2015-02-23
      相关资源
      最近更新 更多