JPA / Hibernate에서 flush ()의 올바른 사용


110

flush () 메소드에 대한 정보를 수집하고 있었지만 언제 사용하고 올바르게 사용하는지 명확하지 않습니다. 내가 읽은 바에 따르면 지속성 컨텍스트의 내용이 데이터베이스와 동기화 될 것임을 이해했습니다. 즉, 미해결 문을 발행하거나 엔티티 데이터를 새로 고칩니다.

이제 두 개의 엔터티 AB(일대일 관계이지만 JPA에 의해 적용되거나 모델링되지 않은) 다음 시나리오가 있습니다. A수동으로 설정되고 자동 생성 된 IDENTITY 필드도있는 복합 PK가 있습니다 recordId. 이것은 recordId엔티티 B에 대한 외래 키로 작성되어야합니다 A. 저는 저축 A하고 B있으며 단일 거래입니다. 문제 A.recordId는를 호출 한 em.flush()후 명시 적으로 호출하지 않는 한 트랜잭션 내 에서 자동 생성 된 값을 사용할 수 없다는 것 em.persist()입니다 A. (자동 생성 된 IDENTITY PK가있는 경우 값이 엔티티에서 직접 업데이트되지만 여기서는 그렇지 않습니다.)

em.flush()거래 내에서 사용할 때 해를 끼칠 수 있습니까 ?

답변:


148

아마도의 정확한 세부 사항 em.flush()은 구현에 따라 다릅니다. 어쨌든 일반적으로 Hibernate와 같은 JPA 공급자는 트랜잭션을 실제로 커밋 할 때까지 종종 데이터베이스로 보내야하는 SQL 명령을 캐시 할 수 있습니다. 예를 들어를 호출 em.persist()하면 Hibernate는 데이터베이스를 INSERT로 만들어야한다는 것을 기억하지만 트랜잭션을 커밋 할 때까지 실제로 명령을 실행하지 않습니다. Afaik, 이것은 주로 성능상의 이유로 수행됩니다.

어쨌든 어떤 경우에는 SQL 명령이 즉시 실행되기를 원합니다. 일반적으로 자동 생성 키 또는 데이터베이스 트리거와 같은 일부 부작용의 결과가 필요할 때.

어떤 em.flush()일은 내부 SQL 명령어 캐시를 비우, 데이터베이스에 즉시 실행하는 것입니다.

결론 : 해를 끼치 지 않습니다. SQL 명령을 데이터베이스에 보내는 최적의 타이밍과 관련하여 JPA 공급자 결정을 재정의하기 때문에 (사소한) 성능 저하가 발생할 수 있습니다.


1
그가 말한 것. em.flush () 동작은 버퍼링 된 모든 데이터가 적절한 대상으로 전송되는 java.io.Flushable.flush ()를 에코합니다.
Erik

4
flush ()가 데이터베이스로 데이터를 보내는 경우? 그 후에 예외가 발생하면 어떻게됩니까? 엔티티 관리자가 모든 것을 롤백합니까? 첫 번째 플러시에서 기록 된 데이터조차?
Jaime Hablutzel 2011-06-17

101
flush ()는 INSERT, UPDATE 등과 같은 데이터베이스에 SQL 명령어를 보냅니다. COMMIT를 보내지 않으므로 flush () 이후에 예외가 발생하면 여전히 완전한 롤백을 할 수 있습니다.
Flavio

17
DB를 롤백 할 수는 있지만 객체에 대한 변경 사항 (예 : 자동 증가 된 '버전', 자동 생성 된 ID 등)은 롤백되지 않습니다. 또한 롤백 후에 엔티티 관리자가 닫힙니다. 객체를 다른 세션에 '병합'하려고하면 특히 자동 증가 '버전'으로 인해 OptimisticLockException이 발생할 수 있습니다.
피터 데이비스

11
부작용을 유발하는 것 외에도 flush ()를 사용하는 또 다른 이유는 JPQL / HQL (예 : 테스트)을 사용하여 데이터베이스에서 작업의 효과를 읽을 수 있기를 원하는 경우입니다. JPA는 이러한 쿼리를 실행할 때 캐시 된 데이터를 사용할 수 없으므로 실제로 DB에있는 항목 만 읽습니다.
sleske 2011

2

사실은, em.flush() 는 캐시 된 SQL 명령을 보내는 것 이상을 수행합니다. 지속성 컨텍스트를 기본 데이터베이스와 동기화하려고합니다. 캐시에 동기화 할 컬렉션이 포함 된 경우 프로세스에 많은 시간이 소요될 수 있습니다.

사용에 대한주의.


1

em.flush ()는 트랜잭션 내에서 사용할 때 해를 끼칠 수 있습니까?

예, 필요 이상으로 오랫동안 데이터베이스에 잠금을 유지할 수 있습니다.

일반적으로 JPA를 사용할 때 트랜잭션 관리를 컨테이너 (일명 CMT-비즈니스 메소드에 @Transactional 어노테이션 사용)에 위임합니다. 즉, 메소드에 들어갈 때 트랜잭션이 자동으로 시작되고 마지막에 커밋 / 롤백됩니다. EntityManager가 데이터베이스 동기화를 처리하도록하면 SQL 문 실행은 커밋 직전에만 트리거되어 데이터베이스에서 잠깐 동안 잠금이 발생합니다. 그렇지 않으면 수동으로 플러시 된 쓰기 작업이 수동 플러시와 자동 커밋 사이에 잠금을 유지할 수 있으며 이는 남은 메서드 실행 시간에 따라 오래 걸릴 수 있습니다.

일부 작업은 자동으로 플러시를 트리거합니다. 동일한 세션에 대해 네이티브 쿼리 실행 (SQL 쿼리에서 도달하려면 EM 상태를 플러시해야 함), 네이티브 생성 ID를 사용하여 엔티티 삽입 (데이터베이스에서 생성되므로 insert 문은 따라서 EM은 생성 된 ID를 검색하고 관계를 적절히 관리 할 수 ​​있습니다.)

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.