JPA 스터디를 하면서 배운 내용을 토대로 하여 Spring Data JPA를 더 유연하게 사용하기 위해 토이프로젝트를 진행했다.
이슈사항이 될 수도 있겠다 싶어서 삽질 아닌 삽질을 하다가 알게된 사실이다.
코드로 보면 아래와 같은 궁금증이었다.
@Test
void findById() {
memberRepository.save(member);
Optional<Member> result = memberRepository.findById(1L);
result.ifPresent(m -> {
assertThat(m.getName()).isEqualTo("홍길동");
});
}
@Test
void findAll() {
memberRepository.save(member);
List<Member> list = memberRepository.findAll();
assertThat(list.size()).isEqualTo(0);
}
이렇게 두 메서드 이다.
결과부터 보자면
findById
findAll
결과가 다르다. 아무 sql을 출력해주지 않는다.
이유는 findAll
을 하면 해당 테이블에 있는 모든걸 가져와야 하니까 update
를 해야한다.
이 트랜잭션 밖에서 무슨일이 벌어져서 해당 테이블에 무슨 변화가 있었는지 모른다.
그래서 실행 전에 update
도 발생한다❗
현재 트랜잭션 안에서 벌어진 일도 반영하고 select를 해야 현재 가장 최신 상태의 데이터를 가져오는거니까 동기화를 하는 느낌? 이라고 생각하면 될것같다.
근데 findById
는 한건에 대한 데이터고, 그 한 건이 현재 트랜잭션 안에서 변경중인 데이터이다. 그래서 해당 변경 사항은 이미 영속성 컨텍스트가 관리하는 중이었기 때문에 findAll
처럼 update
나 select
가 발생할 필요없이, 영속성 컨텍스트 안에서 캐싱하고 있던 객체를 찾아주기 때문에 update
와 select
모두 발생하지 않은것 처럼 보인다. 근데 해당 코드가 테스트가 아니라 일반 애플리케이션 코드였으면 트랜잭션 끝나고 update
가 발생한다.
이게 왜 발생한다고 말을 할 수 있냐면 실제로 한 메서드 내의 트랜잭션에서 save
를 빼고 다른 트랜잭션에서 save
를 해주고 findById
만 조회하면 또 잘나오게 된다.
JPA를 사용함에 있어서 트랜잭션 정말 중요하다는걸 또 한번 깨닫는다❗
데이터를 원하는 조건에 맞게 추출하게 로직을 구현하는건 중요하지만 그 전에 트랜잭션 관리가 최우선이다. 앞으로 더 참고해서 개발해보도록 하자 😁