Jpa의 쓰기지연 때문에 발생한 문제, flush()로 해결하자

Alex·2025년 1월 10일
0

Plaything

목록 보기
71/118

테스트를 하면서

프로필 이미지 모니터링 용으로 만든 엔티티에 프로필 이미지의 id가 맵핑이 되지 않는 문제가 발생했다.

설계는 위처럼 돼 있다.
외래키 제약조건 때문에 ProfileImage를 삭제하는 과정이 번거로워져서
FK 제약조건을 사용하지 않는다.

Profile에 이미지를 맵핑하고, 각각 이미지들에 대해서 Registration을 만들어주는 방식이다.
ProfileRegistration은 만들어졌지만 ProfileImage의 id는 맵핑되지 않은 상황이다.

flush()를 사용하자

이렇게 flush()를 사용하자.

이제 ProfileImageRegistration에 ProfileImage의 id가 정상적으로 맵핑된다.

ProfileImage가 DB에 아직 insert가 안 된 상태라서 id가 아직 만들어지지 않은 상태로 보인다.

IDENTITY으로 식별자를 생성하면 엔티티를 데이터베이스에 저장해야 식별자를 구할 수 있다. 그러니 flush를 하지 않으면 ID가 생기지 않는 것이다.

언제 ID가 만들어지는지 봐보자

우선, Profile에 ProfileImage를 넣는 코드단에서는
ProfileImage의 id가 생성되지 않은 상태다.

ProfileImage를 insert하는 쿼리도 나가지 않았다.

이제 flush가 된 이후를 확인해보자.

insert 쿼리가 발생했다.

flush 이후에는 ProfileImage에 id가 맵핑돼 있다.

결과적으로, JPA 쓰기 지연 때문에 쿼리가 안 나갔던 것으로 보인다.

flush 작동 원리를 확인해보자

디버깅을 해보면
SessionImpl의 flush()를 사용하게 된다.

쭉쭉 들어가면 이렇게 flush를 하는 동작들이 나온다.

내부 원리는 매우 복잡하지만 그냥 1차 캐시에 담아둔 걸 DB로 전송하는 흐름으로 보인다.

baeldung에 따르면

The flush() method is used to synchronize any changes made to entities managed by persistence context with the underlying database. When we invoke flush() on the EntityManager, the JPA provider in turn executes any SQL statements required to persist or update the entities in the database.

flush는 영속성 캐시에 생긴 변화를 DB에 동기화시키는 API이다. 이를 사용함면 JPA는 SQL문을 실행시킨다.
(commit과 다르다. commit까지 해야 db 디스크에 영속적으로 변화가 생긴다)

profile
답을 찾기 위해서 노력하는 사람

0개의 댓글