강의

멘토링

로드맵

Inflearn brand logo image

인프런 커뮤니티 질문&답변

jayjoy05님의 프로필 이미지
jayjoy05

작성한 질문수

자바 ORM 표준 JPA 프로그래밍 - 기본편

영속성 컨텍스트 flush에 들어가는 쿼리 기준이 궁금합니다

작성

·

79

·

수정됨

0

[질문 템플릿]
1. 강의 내용과 관련된 질문인가요? 예
2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? 예
3. 질문 잘하기 메뉴얼을 읽어보셨나요? 예

[질문 내용]
영한님 안녕하세요

Spring Data JPA를 사용해서 벌크 연산 관련해서 공부하던 중에 이상한 점을 발견했습니다. (Spring Data JPA 지만 영속성 컨텍스트 flush는 이 강의와 관련이 깊다 생각해 이 강의에 질문 드립니다)

 

 


..... 우선 실제 제가 겪었던 상황의 코드가 아닌 다른 같은 상황의 예제 코드이기 때문에 완전하지 않은 점 양해 부탁드립니다.. 3개의 엔티티 (User, UserRole, Comment) 가 존재하고 연관관계 매핑 및 외래키 제약조건은 존재하지 않습니다.

 


// 코드 ~~

List<User> userList = new ArrayList<>();


// 코드 ~~~~

userRepository.saveAll(userList); // 저장

userRoleRepository.save(user_role_map); // 저장

Comment c = new Comment("1", "코멘트");

commentRepository.save(c); // 저장 
// 코멘트는 제가 직접 객체를 생성해서 테스트 해보려고 추가하였습니다. 로직과는 관련없습니다.


// 위의 userList와 다른 리스트 
updateName(userListToUpdate);

public interface UserRepository extends JPARepository<User,Long> {
    @Modifying(clearAutomatically = true)
    @Query(UPDATE User u SET u.name ="AA" WHERE u IN :users)
    int updateName(@Param("users") List<User> users);
}

User에 대해 벌크연산을 진행했습니다.

여기서, userList가 비어있고,

userRole와 Comment c에 대해 insert 쿼리가 나가지않고 벌크 연산 업데이트만 진행됩니다..! 이 부분은 당연히 영속성 컨텍스트가 clear 됐기 때문에 그런거라고 이해했습니다.

 

하지만, userList가 비어있지 않은 경우에는 saveAll로 인해 insert 쿼리가 나가면서 userRole, c 까지 모두 insert 쿼리가 실행되는데 이 부분이 잘 이해가 가질 않습니다...

요약하면, user에 대해 insert 쿼리가 실질적으로 나갈 때에만 다른 엔티티들도 @Modifying(clearAutomatically = true) 되면서 같이 insert 쿼리가 나가고, 비어있지않은 경우에는 insert 쿼리가 나가질 않습니다.

이 벌크 연산이 User에 대한 것이기 떄문에 user에 대한 동기화쿼리는 나가고, 그게 나가면서 다른 엔티티까지 같이 나가는 원리일까요? userRole과 comment는 모두 연관관계매핑도 되어있지않은데 왜 insert 쿼리가 같이 나가는지 궁금합니다

 

 

 

 

 

답변 2

0

김영한님의 프로필 이미지
김영한
지식공유자

안녕하세요. jayjoy05님

하이버네이트는 JPQL을 실행할 때 기본적으로 플러시를 먼저 수행하고 JPQL을 수행합니다. 따라서 UPDATE User u SET u.name ="AA" WHERE u IN :users JPQL 쿼리가 실행되기 직전에 먼저 플러시가 수행되어야 합니다.

그런데 하이버네이트 내부에 최적화 로직이 있습니다. JPQL이 현재 User를 대상으로 하는 JPQL이기 때문에 User 엔티티에 변경 사항이 없다면 플러시를 수행하지 않습니다.

이 경우 User 엔티티가 영속성 컨텍스트에 없고, 따라서 변경사항이 없습니다. 이 경우 JPQL을 수행하기 직전에 플러시가 수행되지 않습니다.

그리고 쿼리 수행 이후 바로 clearAutomatically에 의해서 영속성 컨텍스트가 초기화 되어버린 것입니다.

감사합니다.

0

안녕하세요, 인프런 AI 인턴입니다. jayjoy05님.

질문을 주신 사항은 JPA의 영속성 컨텍스트와 JPQL 벌크 연산의 동작 방식에 대한 이해가 필요합니다.

일반적으로 JPA에서 엔티티에 대한 변경 사항은 영속성 컨텍스트에 유지되다가 트랜잭션이 커밋될 때 flush 과정을 통해 데이터베이스에 반영됩니다. JPQL 벌크 연산의 경우, 특정 엔티티에 대한 대량 업데이트를 DB에 직접 수행하는데, 이때 JPA는 자동으로 flush를 호출하여 영속성 컨텍스트의 변경 사항을 DB에 반영하고 엔티티의 상태를 초기화합니다.

그러나 질문에서처럼 이전에 saveAll로 여러 엔티티가 영속화된 후에, 빈 리스트로 벌크 업데이트가 호출되면, 해당 벌크 연산에 영향을 받는 엔티티가 없어서 트리거되어야 할 flush 이벤트가 발생하지 않을 수도 있습니다. 이는 영속성 컨텍스트의 데이터 동기화와 관련된 JPA의 내부 최적화 동작 일 가능성이 큽니다.

관련된 질문 중에 유사한 내용을 다루고 있는 글이 있습니다. @Modifying에 관한 질문을 참조해 보시기 바랍니다. 이 글에서는 JPA의 flush와 clearAutomatically 옵션에 관한 김영한님의 설명을 확인할 수 있습니다.

여기서 중요한 점은, 벌크 연산 시 flush는 자동으로 수행되지만, 벌크 연산이 영속성 컨텍스트의 엔티티를 실제로 변경하지는 않는다는 것입니다. 따라서, 벌크 연산 후에는 반드시 영속성 컨텍스트를 초기화(clear)하여 일관된 상태를 유지해야 합니다.

저는 질문자님의 이해를 돕고자 지식공유자님의 기존 답변을 참고하여 유사한 답변 링크를 추천해드리고 있습니다. 현재 베타 기능으로 답변이 만족스럽지 않을 수 있는 점 양해 부탁드립니다. 🙏 추가적으로 궁금한 점이 있으시면, 이어서 질문해 주세요. 곧 지식공유자께서 답변해 주실 것입니다.

jayjoy05님의 프로필 이미지
jayjoy05

작성한 질문수

질문하기