복붙노트

[SPRING] 큰 트랜잭션 도중에 Hibernate 세션을 안전하게 지운다.

SPRING

큰 트랜잭션 도중에 Hibernate 세션을 안전하게 지운다.

글자 그대로 수십만 개의 항목을 생성하고 업데이트해야하는 작업을 위해 Spring + Hibernate를 사용하고 있습니다. 이 같은:

{
   ...
   Foo foo = fooDAO.get(...);
   for (int i=0; i<500000; i++) {
      Bar bar = barDAO.load(i);
      if (bar.needsModification() && foo.foo()) {
         bar.setWhatever("new whatever");
         barDAO.update(bar);
         // commit here
         Baz baz = new Baz();
         bazDAO.create(baz);
         // if (i % 100 == 0), clear
      }
   }
}

중간에 변경 사항이 손실되지 않도록 자신을 보호하기 위해 barDAO.update (bar) 바로 다음에 변경 사항을 커밋합니다.

HibernateTransactionManager transactionManager = ...; // injected by Spring
DefaultTransactionDefinition def = new DefaultTransactionDefinition();
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
TransactionStatus transactionStatus = transactionManager.getTransaction(def);
transactionManager.commit(transactionStatus);

이 시점에서 전체 프로세스가 org.springframework.orm.hibernate3.support.ExtendedOpenSessionInViewFilter로 래핑 된 트랜잭션에서 실행되고 있다고 말할 수 있습니다 (예, 이것은 웹 애플리케이션입니다).

이것은 한가지 예외를 제외하고는 모두 잘 작동합니다 : 수천 건의 업데이트 / 커밋 후에 전체 프로세스가 실제로 느려지는데, 이는 Spring / Hibernate에 의해 보관되는 객체의 증가하는 양에 의해 메모리가 부풀어 오르기 때문일 가능성이 큽니다.

Hibernate-only 환경에서 이것은 org.hibernate.Session # clear ()를 호출함으로써 쉽게 풀 수있다.

자, 질문 :

답변 해 주셔서 감사합니다.

해결법

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

    1.일정한 간격으로, 이상적으로 JDBC 배치 크기와 동일합니다. 변경 후 플러시됩니다. 이 문서는 일괄 처리에 대한 장의 일반적인 관용구를 설명합니다.

    일정한 간격으로, 이상적으로 JDBC 배치 크기와 동일합니다. 변경 후 플러시됩니다. 이 문서는 일괄 처리에 대한 장의 일반적인 관용구를 설명합니다.

    그리고 이것은 성능 비용이 없어야합니다.

    엔티티를 추적하지 않으려면 세션을 명시 적으로 지워야합니다. 즉, 엔티티를 추적하지 않아도됩니다 (엔티티를 "손실"하지 않고 트랜잭션을 커밋하려고 할 수 있습니다).

    그러나 내가 볼 수있는 바에서 bar와 baz 인스턴스는 명확한 후에 GC 후보가되어야합니다. 메모리 덤프를 분석하여 정확히 무슨 일이 일어나는지 보는 것은 흥미로울 것입니다.

    당신이 원하는대로하지 않는 한 보류중인 변경 사항을 플러시하지 않는 한, 나는 아무런 문제도 보이지 않는다. (현재 코드는 매 100 루프를 만들지는 모르겠지만 어쩌면 단지 의사 코드 일 뿐이다.) ).

    clear ()를 호출하면로드 된 모든 인스턴스가 세션에서 제거되어 분리 된 엔터티가됩니다. 후속 호출에서 엔티티가 "연결"되어야하는 경우 실패합니다.

  2. ==============================

    2.세션을 지우고 나면 세션에 있던 객체를 계속 사용하려면 계속하려면 Session.refresh (obj)를 사용해야한다는 점을 지적하고자합니다.

    세션을 지우고 나면 세션에 있던 객체를 계속 사용하려면 계속하려면 Session.refresh (obj)를 사용해야한다는 점을 지적하고자합니다.

    그렇지 않으면 다음 오류가 발생합니다.

    org.hibernate.NonUniqueObjectException
    
  3. from https://stackoverflow.com/questions/3788048/safely-clearing-hibernate-session-in-the-middle-of-large-transaction by cc-by-sa and MIT license