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

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

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

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



답변

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

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

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

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


답변

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

사용에 대한주의.


답변

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

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

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

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


답변