프로그래밍/JPA

flush와 clear의 차이 (테스트 코드에서 SELECT가 안나가는 이유)

승민아 2024. 3. 8. 18:08

테스트 코드를 작성하는중에 문제가 발생했다.

 

먼저, 장소와 게시글의 관계는 1:N 관계이다.

다음의 테스트 코드를 보자.

Location location = new Location();
location.setTitle("테스트 장소");
locationRepository.save(location);

Poster poster = new Poster();
poster.setTitle("게시글1");
poster.setLocation(location);
posterRepository.save(poster);

Poster poster2 = new Poster();
poster2.setTitle("게시글1");
poster2.setLocation(location);
posterRepository.save(poster2);

Location findLocation = locationRepository.findById(location.getId()).get();
int size = findLocation.getPosters().size();

 

장소에 게시글을 2개 작성하고 DB에 저장한다.

그리고 나는 장소를 DB에서 조회하여 게시글의 개수를 출력해보길 원했다.

 

그러나 의도와 달리 findById의 실행으로 인한 SELECT 쿼리는 나가지 않았고

findLocation의 게시글 size 또한 0으로 나왔다.

 

왜 SELECT가 나가지 않았을까?

 

영속성 컨텍스트와 관련이 있다.

https://non-stop.tistory.com/482

 

영속성 컨텍스트 장점중 하나가 "1차 캐시"가 있다.

내가 DB에서 엔티티를 조회하기위해 다음과 같은 코드를 작성했더라도 바로 DB에 조회를 요청하지 않는 것이다.

Location findLocation = locationRepository.findById(location.getId()).get();

 

왜냐.

엔티티를 위에서 save 했을때 1차 캐시에 저장되기 때문에

내가 DB를 통해 찾으려고해도 1차 캐시에 존재하는 데이터를 가져오기 때문이다.

 

그럼 위의 상화에서 DB를 통해 조회하고싶다면 어떻게 해야할까?

 

em.clear() 를 추가해서 영속성 컨텍스트를 한번 초기화 시켜버리자!

(
@Autowired
EntityManager em;
)

...

Poster poster2 = new Poster();
poster2.setTitle("게시글1");
poster2.setLocation(location);
posterRepository.save(poster2);

em.clear();

Location findLocation = locationRepository.findById(location.getId()).get();
int size = findLocation.getPosters().size();
Assertions
    .assertThat(size)
    .isEqualTo(2);

 

그러면 영속성 컨텍스트에 존재하지 않기에 DB에서 가져오기 위해 SELECT 쿼리가 나간다.!

 

처음에 flush로 해결하고자 했으나 flush와 clear은 명확히 차이가 있다.

 

flush는 영속성 컨텍스트의 변경 사항과 쿼리들을 반영하기 위한 것이지

flush를 실행한다고해서 1차 캐시가 삭제되는것이 아니다!!