Quarkus에서 배치 실행을 위해 프로그래밍 방식으로 Hibernate Commit 제어

배치 실행 중 커밋이 많은 문제



배치 실행에서 엄청난 양의 데이터를 처리해야 하는 경우 Hibernate가 수행하는 커밋 수를 제어하는 ​​것이 중요합니다.

커밋은 가장 비용이 많이 드는 데이터베이스 작업 중 하나입니다.

@Transactional 주석 사용



Quarkus에서는 @Transactional 주석을 사용하여 커밋 실행을 제어할 수 있습니다. @Transactional 주석이 달린 메서드가 성공적으로 완료되면 Hibernate는 하나의 커밋을 데이터베이스로 보냅니다.

import javax.transaction.Transactional;
//
@Transactional(rollbackOn = Exception.class)
public void processClientOrders(Client client) {
     client.updateOrders();
     client.insertHistory();
     client.updateClient();
}


위의 예에서 processClientOrders()가 완료되면 Hibernate는 하나의 커밋을 데이터베이스로 보냅니다.

배치 실행을 제어하기 위해 @Transactional 주석을 사용하는 데 어려움이 있음



배치 실행에서는 처리된 항목의 양이나 커밋 사이의 시간을 사용하여 커밋 수를 제어하는 ​​것이 좋습니다.

내 관점에서 특히 커밋 사이의 시간을 제어하기 위해 @Transactional 주석을 사용하여 이것을 제어하기가 약간 어렵습니다.

프로그래밍 방식으로 커밋 실행



여기서 제공하려는 기여는 프로그래밍 방식을 사용하여 커밋을 제어하는 ​​한 가지 아이디어입니다.

애플리케이션에서 커밋 매개변수 정의



이 항목은 필수는 아니지만 좋은 생각이라고 생각합니다. 이 접근 방식을 사용하면 배포 시 값을 조정할 수 있습니다.
application.properties에서 두 개의 매개변수를 정의합니다.

# Minimum quantity of items processed to execute commit
app.quantity.of.items.to.commit=1000

# Minimum quantity of time (milliseconds) to execute commit
app.quantity.of.time.ms.to.commit=1000


프로그래밍 방식으로 트랜잭션 제어



트랜잭션을 프로그래밍 방식으로 제어하려면 UserTransaction를 삽입한 다음 수동으로 트랜잭션을 시작하고 커밋해야 합니다.

@Inject
UserTransaction transaction;

@ConfigProperty(name = "app.quantity.of.items.to.commit")
int quantityItemsCommit;

@ConfigProperty(name = "app.quantity.of.time.ms.to.commit")
int quantityTimeCommit;

public void batchProcess(List<Client> listOfClients)
                 throws SystemException,NotSupportedException, 
                 SecurityException, IllegalStateException,
                 RollbackException, HeuristicMixedException,  
                 HeuristicRollbackException {
  var beforeCommit = Instant.now();
  var quantityOfClientsPendingCommit = 0;
  transaction.begin();

  for (Client client : listOfClients ) {
    processClientOrders(client);
    var now = Instant.now();
    var delay = Duration.between(beforeCommit, now).toMillis();
    if (++quantityOfClientsPendingCommit >= quantityItemsCommit  
        || delay >= quantityTimeCommit) { 
      transaction.commit();
      transaction.begin();
      beforeCommit = Instant.now();
      quantityOfClientsPendingCommit = 0;
    }
  }
  transaction.commit();
}

private void processClientOrders(Client client) {
     client.updateOrders();
     client.insertHistory();
     client.updateClient();
}


위의 코드는 처리되는 클라이언트의 양이 제한보다 크거나 같거나 마지막 커밋 후 시간이 제한보다 크거나 같을 때 커밋을 실행합니다.

최종 단어



이 기사가 뭔가를 추가할 수 있기를 바라며, 내가 한 실수를 발견하거나 이 개념을 개선할 아이디어가 있으면 의견을 말하십시오.

학점



Stack Overflow post about calculating time in milliseconds

Red Hat documentation about Managing JTA transactions programmatically

좋은 웹페이지 즐겨찾기