2017-09-18 5 views
2

나는 세 개의 @Transactional @Async 메쏘드를 호출하는 시나리오를 가지고있다. 모든 세 가지 방법은 자신의 트랜잭션 컨텍스트를 제외하고 잘 작동합니다. 메서드의 트랜잭션 컨텍스트를 호출하여이를 실행하려고합니다.@Async 메소드에서 @ Transactional @

내 소명 방법은 다음과 같이이다 :

@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을 사용하지 않으면 잘 작동합니다. 내가 평행하게 달릴 수 있도록 시간을 보내는 방법이 있습니다.

해결 방법을 제안하십시오.

+1

'@ Async' 메소드는 별도의 스레드에서 실행되므로 호출자의 동일한 트랜잭션을 사용할 수 없습니다. –

답변

1

프로그래밍 방식으로 제어하려면 스프링 TransactionTemplate을 사용해야합니다.
주 스레드가 제어를 수행해야합니다. 스레드가 예외를 throw하면 다른 스레드에게 롤백해야 함을 알려야합니다.

실행 후 각 "트랜잭션"스레드는 이어야하며 스레드에서 트랜잭션 커밋을 수행해야합니다. 예외가 발생하면 Thread.interrupt()을 호출하고 롤백해야합니다.