복붙노트

[SPRING] 완성 가능한 미래 대 봄 거래

SPRING

완성 가능한 미래 대 봄 거래

생각

처리 방법은 항목 목록을 가져 와서 외부 웹 서비스를 사용하여 비동기 적으로 처리하는 처리 방법입니다. 프로세스 단계는 또한 처리하는 동안 데이터를 유지합니다. 전체 프로세스가 끝나면 전체 프로세스를 각 처리 된 결과와 함께 유지하기를 원합니다.

문제

목록의 각 항목을 CompletableFuture로 변환하고 처리 작업을 실행하여 미래의 배열로 되돌립니다. 이제 제출 된 모든 작업이 완료 될 때 미래를 완료하고 그 결과를 보유하는 다른 CompletableFuture를 반환하는 .ofAll 메서드 (시퀀스 메서드)를 사용합니다.

그 결과를 얻으 려 할 때 .whenComplete (..)를 호출하고 반환 된 결과를 데이터로 내 엔터티에 설정 한 다음 데이터베이스에 유지하려고하지만 리포지토리 저장 호출은 아무 것도하지 않고 스레드 만 계속 처리합니다. 계속 실행하면 저장소 저장 호출을 지나치지 않습니다.

 @Transactional
 public void process(List<Item> items) {
   List<Item> savedItems = itemRepository.save(items);

   final Process process = createNewProcess();

   final List<CompletableFuture<ProcessData>> futures = savedItems.stream()
     .map(item -> CompletableFuture.supplyAsync(() -> doProcess(item, process), executor))
     .collect(Collectors.toList());

   sequence(futures).whenComplete((data, throwable) -> {
     process.setData(data);
     processRepository.save(process); // <-- transaction lost?
     log.debug("Process DONE"); // <-- never reached
   });
  }

시퀀스 방법

 private static <T> CompletableFuture<List<T>> sequence(List<CompletableFuture<T>> futures) {
    CompletableFuture<Void> allDoneFuture =
      CompletableFuture.allOf(futures.toArray(new CompletableFuture[futures.size()]));
    return allDoneFuture.thenApply(v ->
      futures.stream().map(CompletableFuture::join).collect(Collectors.toList())
    );
  }

무슨 일 이니? 지속 호출이 전달되지 않는 이유는 무엇입니까? 트랜잭션을 시작한 스레드가 트랜잭션을 커밋 할 수 없거나 손실 된 위치는 어디입니까? 모든 처리 된 데이터가 정상적으로 반환되며 모두 양호합니다. 다른 거래 전략을 시도했지만 트랜잭션이 완료 될 때 어떤 스레드가 트랜잭션을 완료 할지를 제어하는 ​​것이 어떻게 가능합니까?

어떤 충고?

해결법

  1. ==============================

    1.위와 같이 문제가 발생한 이유는 트랜잭션이 종료된다는 것입니다. 메소드 반환 과정 (..)에 도달했을 때.

    위와 같이 문제가 발생한 이유는 트랜잭션이 종료된다는 것입니다. 메소드 반환 과정 (..)에 도달했을 때.

    할 수있는 일은 수동으로 트랜잭션을 생성하는 것입니다. 시작과 끝 시간을 제어하십시오.

    @ Transactional 삭제

    프로세스 (..)에서 TransactionManager를 Autowire하십시오.

        TransactionDefinition txDef = new DefaultTransactionDefinition();
        TransactionStatus txStatus = transactionManager.getTransaction(txDef);
        try {
        //do your stuff here like
            doWhateverAsync().then(transactionManager.commit(txStatus);)
        } catch (Exception e) {
            transactionManager.rollback(txStatus);
            throw e;
        }
    
  2. ==============================

    2.Spring Boot Application의 경우 다음과 같은 설정이 필요합니다.

    Spring Boot Application의 경우 다음과 같은 설정이 필요합니다.

    주요 응용 프로그램 메서드에는 @EnableAsync 주석이 있어야합니다.

    @Async 어노테이션은 @Transactional 어노테이션이있는 메소드의 맨 위에 있어야합니다. 이것은 자식 스레드에서 처리가 수행됨을 나타 내기 위해 필요합니다.

  3. from https://stackoverflow.com/questions/35628764/completablefuture-vs-spring-transactions by cc-by-sa and MIT license