• 카테고리

    질문 & 답변
  • 세부 분야

    백엔드

  • 해결 여부

    해결됨

em.flush 발생 시점에 대한 부가적인 질문

23.12.11 15:00 작성 조회수 220

0

오랜만에 관련된 업무 진행하다가 발생한 궁금점에 대하여 질문드리게 되었습니다. 우선 한 트랜젝션의 영속성 컨텍스트에 대하여 쓰기 지연 저장소에 쌓인 쿼리가 flush() 되는 경우는 다음 세 가지로 이해하였습니다.

 

  • flush() 직접호출

  • 트랜젝션 commit()

  • JPQL 직접 발생시, 해당 JPQL 발생 이전

     


다음과 같은 연관관계가 가정되어 있다고 해보겠습니다.

    public class Car{
        @Id
        private Long id;
    }
    
    public class Wheel {
        @Id
        private Long id;
        
        @ManyToOne
        @JoinColumn(name = "car_id")
        private Car car;
    }

 

Wheel 이 연관관계의 주인이며, Car 와 M:1 관계로 매핑되어 있습니다.

이 때, 다음과 같은 로직을 수행해보겠습니다. (1L 의 Wheel 이 2L 의 Car 에 매핑되어 있음)

Wheel wheel = em.find(Wheel.class, 1L);
wheel.setCar(null);    // 1) 

em.createQuery("delete from Car c where c.id = :id")
    .setParameter("id", 2L)
    .exeucteUpdate();    // 2)

 

이와 같이 수행되었을 때,

1번 시점에서 영속성 컨텍스트에 보관중인 Wheel 의 Car 값이 변경되어 Update 쿼리가 발생하여 쓰기 지연 저장소에 저장되었을 것으로 추측합니다.

2번 시점은 위에서 말한 'flush 발생시점' 중 3번에 해당한다고 생각했습니다 (JPQL 직접 수행). 그렇다면 쓰기 지연 저장소에 쌓인 Update 쿼리가 나간 이후, 직접 수행하려는 Delete JPQL 을 발생시켜서 아무 문제 없이 수행되어야 하는거 아닌가 싶었는데, 위 로직은 FK 제약조건에 위배되어 수행되지 못합니다.

 

1번과 2번 사이에 강제로 em.flush() 를 진행해주면, 그제서야 update 쿼리가 발생한 뒤에 delte 쿼리가 발생하여 위 로직이 아무 에러 없이 수정되는 모습을 확인했습니다.

왜 이 상황에서는 flush 가 자동으로 발생하지 않나요? 열심히 찾아봤을 때... JPA 측에서 제공하는 3번 (JPQL 발생시 flush 됨) 에 대한 명확한 [기준] 은 제시하고 있지 않은 것으로 보이는데 맞을까요??


답변 1

답변을 작성해보세요.

0

y2gcoder님의 프로필

y2gcoder

2023.12.11

안녕하세요. 강우석님, 공식 서포터즈 y2gcoder입니다.

위의 쿼리를 보니 벌크성 업데이트 쿼리(executeUpdate)를 사용하셨습니다!

벌크성 업데이트 는 영속성 컨텍스트를 이용하지 않고 바로 데이터베이스로 쿼리를 날리게 됩니다!

1번 내용이 반영되기 전에 바로 데이터베이스로 쿼리를 날리기 때문에 에러가 발생하게 됩니다 :)

본 강의의 섹션 11.객체지향 쿼리 언어2 - 중급 문법 의 마지막 벌크 연산에서 다루고 있으니 참고해보시면 좋을 것 같습니다!

 

감사합니다.