Program Tip

최대 절전 모드 : flush () 및 commit ()

programtip 2020. 11. 9. 20:30
반응형

최대 절전 모드 : flush () 및 commit ()


org.hibernate.Session.flush()별도로 전화하는 것이 좋은 습관 입니까?

org.hibernate.Session문서에서 말했듯이

트랜잭션을 커밋하고 세션을 닫기 전에 작업 단위가 끝날 때 호출되어야합니다 (플러시 모드에 따라 Transaction.commit ()이이 메서드를 호출 함).

이미 할 flush()경우 명시 적으로 호출하는 목적을 설명해 주 org.hibernate.Transaction.commit()시겠습니까?


Hibernate 매뉴얼에서이 예제를 볼 수 있습니다.

Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();

for (int i = 0; i < 100000; i++) {
    Customer customer = new Customer(...);
    session.save(customer);
    if (i % 20 == 0) { // 20, same as the JDBC batch size
        // flush a batch of inserts and release memory:
        session.flush();
        session.clear();
    }
}

tx.commit();
session.close();

flush 메서드를 호출하지 않으면 첫 번째 수준 캐시에서 OutOfMemoryException이 발생합니다.

또한 플러싱에 대한이 게시물을 볼 수 있습니다.


flush()데이터베이스를 메모리에 보관 된 개체 / 개체의 현재 상태와 동기화하지만 트랜잭션을 커밋하지는 않습니다. 따라서를 flush()호출 한 후에 예외 발생 하면 트랜잭션이 롤백됩니다. 을 사용하여 flush()한 번에 큰 데이터를 커밋하는 대신을 사용하여 작은 데이터 청크와 데이터베이스를 동기화 할 수 commit()있으며 OutOfMemoryException.

commit()데이터베이스에 저장된 데이터를 영구적으로 만듭니다. commit()성공하면 트랜잭션을 롤백 할 수있는 방법이 없습니다 .


명시 적으로 플러시하는 한 가지 일반적인 경우는 새 영구 엔터티를 생성하고 나중에 동일한 트랜잭션에서 사용할 수 있도록 인공 기본 키를 생성하고 할당하려는 경우입니다. 이 경우 flush를 호출하면 엔티티에 ID가 부여됩니다.

또 다른 경우는 첫 번째 수준 캐시에 많은 항목이 있고 캐시에서 사용하는 메모리 양을 줄이기 위해 주기적으로 지우고 싶지만 전체를 함께 커밋하려는 경우입니다. . 이것은 Aleksei의 답변이 다루는 경우입니다 .


flush();플러싱은 기본 영구 저장소를 메모리에 유지되는 지속 가능한 상태와 동기화하는 프로세스입니다. 실행중인 트랜잭션의 테이블에 업데이트하거나 삽입하지만 이러한 변경 사항을 커밋하지 않을 수 있습니다.

일괄 처리에서 플러시해야합니다 . 그렇지 않으면 OutOfMemoryException 이 발생할 수 있습니다 .

Commit();Commit은 데이터베이스를 커밋합니다. 지속 된 객체가 있고 그 값을 변경하면 더러워지고 최대 절전 모드에서 이러한 변경 사항을 지속성 레이어에 플러시해야합니다. 따라서 커밋해야하지만 작업 단위 ( transaction.commit()) 도 종료됩니다 .


필요한 경우가 아니면 일반적으로 flush를 명시 적으로 호출하지 않는 것이 좋습니다. Hibernate는 일반적으로 트랜잭션이 끝날 때 자동으로 Flush를 호출하며 우리는 그것이 작동하도록해야합니다. 이제 두 번째 작업이 동일한 트랜잭션 내부에있는 첫 번째 지속성 작업의 결과에 따라 달라지는 경우 flush를 명시 적으로 호출해야하는 경우가 있습니다.

예를 들어, 새 엔티티를 유지 한 다음 해당 엔티티의 ID를 사용하여 동일한 트랜잭션 내에서 다른 작업을 수행해야 할 수 있습니다.이 경우 먼저 엔티티를 명시 적으로 플러시해야합니다.

@Transactional
void someServiceMethod(Entity entity){
    em.persist(entity); 
    em.flush() //need to explicitly flush in order to use id in next statement
    doSomeThingElse(entity.getId());    
}

또한 명시 적으로 플러시하면 데이터베이스 커밋이 발생하지 않으며 데이터베이스 커밋은 트랜잭션 끝에서만 수행되므로 플러시를 호출 한 후 런타임 오류가 발생해도 변경 사항은 여전히 ​​롤백됩니다.


기본적으로 플러시 모드는 AUTO입니다. 즉, "쿼리가 오래된 상태를 반환하지 않도록하기 위해 쿼리 실행 전에 세션이 가끔 플러시됩니다."이지만 대부분의 경우 변경 사항을 커밋 할 때 세션이 플러시됩니다. FlushMode = MANUAL을 사용하거나 어떤 종류의 최적화를 수행하려는 경우 flush 메서드를 수동으로 호출하는 것이 유용합니다. 그러나 나는 이것을 한 적이 없으므로 실용적인 조언을 드릴 수 없습니다.


session.flush ()는 동기화 방법으로 데이터를 순차적으로 데이터베이스에 삽입하는 것을 의미합니다.이 방법을 사용하면 데이터는 데이터베이스에 저장되지 않지만 캐시에 저장되며 중간에 예외가 발생하면 처리 할 수 ​​있습니다. 그러나 commit ()은 데이터베이스에 데이터를 저장합니다. 더 많은 양의 데이터를 저장하면 Save point 주제의 JDBC 프로그램과 같이 메모리 부족 예외가 발생할 수 있습니다.

참고 URL : https://stackoverflow.com/questions/14581865/hibernate-flush-and-commit

반응형