[ TIL ] em.find() vs JPQL SELECT

charco·2021년 10월 18일
0

나도TIL

목록 보기
49/55
post-custom-banner

em.find() 와 JPQL select 의 차이

다음의 코드를 보자. (show-sql = true)

em.find(Member.class, 1L);
em.find(Member.class, 1L);

이 코드를 실행하면 몇번의 쿼리가 날아갈까?
잠시 생각해보자...
...
...
...
...

정답은 한번이다.
첫번째 em.find()를 호출하면 먼저 영속성 컨텍스트의 1차 캐시를 탐색해
해당 엔티티가 있는지 확인한다.
1차 캐시에 해당 엔티티가 없으니, DB에 SELECT 쿼리를 날려 엔티티를 1차 캐시에 저장하고 반환한다.
두번째 em.find()가 호출되면 첫번째와 마찬가지로 영속성 컨텍스트의 1차 캐시를 탐색한다. 이번엔 해당 엔티티가 있다.
그래서 DB에 SELECT 쿼리를 날리지 않고 1차 캐시에서 엔티티를 조회해 반환한다.

그렇다면 두번째 코드를 한번 보자.

em.find(Member.class, 1L);
em.createQuery("select m from Member m where m.id = 1")
	.getSingleResult();

몇번의 쿼리가 날아갈까?
잠시 생각해보자...
...
...
...
...

정답은 두번이다.
왜냐하면 JPQL 로 조회를 하면 DB에서 먼저 조회하기 때문이다.
DB에서 조회한 후 영속성 컨텍스트에 해당 엔티티가 존재하는지 확인하고
존재하면 조회한 데이터를 버리고, 존재하지 않으면 영속성 컨텍스트에 조회한 데이터를 저장한다.


FlushModeType.AUTO vs FlushModeType.COMMIT

다음의 코드를 보자.

Member member = em.find(Member.class, 1L);
member.setAge(10);

Member foundMember = 
	em.createQuery("select m from Member m where m.age = 10")
		.getSingleResult();
        

foundMember 가 잘 조회될까?
생각해보자...
...
...
...
...

그렇다 잘 조회된다. 왜 그럴까?
바로 flush mode 가 AUTO가 기본으로 설정돼있기 때문이다.
FlushModeType.AUTO 는 커밋시에, 그리고 JPQL 쿼리를 날리기 전에
flush() 를 호출한다.

따라서 위의 코드가 실행되는 과정은 이렇다.

  1. em.find() 로 Member 엔티티를 조회한다.

  2. 엔티티를 수정한다.

  3. JPQL SELECT 문이 날아가기 전에 flush()가 호출된다. 여기서 UPDATE 쿼리가 날아가 DB의 데이터를 변경한다.

  4. JPQL 의 SELECT 문이 변경된 데이터를 조회한다.

그렇다면 FlushModeType.COMMIT 으로 설정해보자.
FlushModeType.COMMIT 은 커밋시에만 flush()를 호출하게 하는 설정이다.
다음의 코드는 위의 코드에 설정만 추가된 것이다.

em.setFlushMode(FlushModeType.COMMIT);

Member member = em.find(Member.class, 1L);
member.setAge(15);

Member foundMember = 
	em.createQuery("select m from Member m where m.age = 15")
		.getSingleResult();
        

코드가 실행되는 과정은 이렇다.

  1. em.find()로 Member 엔티티를 조회한다.

  2. 엔티티를 수정한다.

  3. FlushModeType 이 COMMIT 이기 때문에 flush()가 호출되지 않는다.

  4. JPQL SELECT 문이 실행된다. 그러나 아무것도 조회하지 못한다.

만약 위의 코드에서 JPQL SELECT 문이 정상적으로 조회되게 하고 싶다면
수동으로 JPQL 쿼리를 날리기 전에 em.flush()를 호출하거나,
TypedQuery 에 setFLushMode() 를 설정하면 된다.

em.setFlushMode(FlushModeType.COMMIT);

Member member = em.find(Member.class, 1L);
member.setAge(20);

//em.flush() 를 호출해 DB와 영속성 컨텍스트를 동기화한다.

Member foundMember = 
	em.createQuery("select m from Member m where m.age = 20")
    		//.setFlushMode(FlushModeType.Auto) // Query 에 직접 설정한다.
		.getSingleResult();
        
profile
아직 배우는 중입니다
post-custom-banner

0개의 댓글