JH 개발 블로그
JPA - SELECT 보다 UPDATE 쿼리가 먼저 나가는 이유 (flush, 변경감지) 본문
주요 키워드 : 1차 캐시, 변경감지, 쓰기 지연, flush
JPA의 flushmode의 기본값은 auto이다.
auto 일때 아래의 조건으로 flush가 실행된다.
- 트랜잭션이 커밋되기 이전
- 영속성 컨텍스트에 보류 중인 변경이 포함된 데이터베이스 테이블을 조회하는 쿼리를 실행하기 전
1. 변경 감지는 항상 flush가 호출되기 직전에 수행된다.
2. flush는 아래의 조건에서 실행된다.
- EntityManager의 flush 메소드를 호출했을 때
- 트랜잭션 커밋시
- JPQL 쿼리 실행시
예시
// 1. pk로 엔티티 조회
Member member = MemberRepository.findById(id);
// 엔티티 필드 수정
member.setGrade(5);
// 2.pk가 아닌 colum으로 엔티티 조회
Member member = MemberRepository.findByPhoneNum(phoneNum);
/// 나머지 쿼리 실행 로직 (생략) ///
위 상황에서 발생 쿼리는
1. select (pk로 조회)
2. update
select (컬럼으로 조회)
순서다. 왜 update가 쿼리가 나가는가 하면..
- 영속성 컨텍스트에 보류 중인 변경이 포함된 데이터베이스 테이블을 조회하는 쿼리를 실행하기 전
위 조건을 만족하기 때문이다.
findByPhoneNum()은 pk가 아닌 컬럼 조회기 때문에, 1차캐시를 조회하지 않고 DB 테이블을 조회한다.
따라서, JPA는 변경사항을 반영하기 위해 flush 직전에 변경감지를 통해 update 쿼리를 짜서 쓰기지연 저장소에 넣고
flush가 실행되는 것이다.
기본적으로 JPA는 트랜잭션 내에서 데이터 일관성을 유지하려고 한다.
위와같이 변경사항 반영이 필요한 타이밍에 flush가 나가는 것이다.
만약 Member를 조회하는게 아니라 전혀 상관없는 다른 테이블을 조회한다면, flush는 발생하지 않는다. flush는 영속성 컨텍스트에 보류중인 '변경'이 포함된 테이블을 조회할때 발생하기 때문이다.
flush는 실제 db에 변경사항을 반영하는게 아니라, 트랜잭션 내에서만 변경사항을 반영한다.
실제 db까지 반영하려면 커밋이 되야한다.
'JAVA' 카테고리의 다른 글
SpringBoot static 변수에 @value 사용 (0) | 2025.01.17 |
---|---|
자바 자료형 변환 정리 (0) | 2022.12.08 |
@AuthenticationPrincipal 사용시 LazyInitializationException (2) | 2022.11.19 |
Java compareTo(), compare()의 차이와 내림차순, NaN값 처리 (0) | 2022.10.27 |
Comments