LinkedIn

Spring JPA findById() 사용 시 주의점

2021. 7. 28. 21:08 | 자바 개발자되기

Spring JPA에서 Entity 조회 시 @Id 어노테이션이 적용되어 있는 필드 메서드 인자 값으로 하여 Optional<T> findById(ID id) 메서드 호출 가능하다.


JpaRepository를 상속받은 경우 SimpleJpaRepository가 구현체로 주입되며 조회 시 아래와 같은 처리가 진행된다.

 

1. 만약 1차 캐시에 조회하고자 하는 Managed Entity가 존재한다면 이를 반환


2. 만약 1차 캐시에 없다면 DB 조회 후 반환


DB에서 조회하기 전 트랜잭션을 생성하게 되는데 이때 트랜잭션 속성의 경우 1) method @Transactional 어노테이션이 있는지 확인하고, 만약 없다면 2) class에 @Transactional 어노테이션 존재 확인


findById() 메서드는 SimpleJpaRepository 클래스의 구현체 메서드로 호출되고, 해당 클래스에는 @Transactional(readOnly = true) 가 적용되어 있음


findById()를 호출 한 상위 메서드에서 별도의 트랜잭션이 생성되어 존재하지 않는다면 SImpleJpaRepository에서 생성된 트랜잭션을 물고 들어가기에 findById()는 readOnly 속성이 적용된다!

 

RW/RO를 별개의 물리적인 Datasource를 사용하고 있다면 readOnly 속성이 적용된 트랜잭션의 경우 RO에서 데이터를 조회하기 때문에 Replica Lag(복제 지연)이 발생할 수 있다.

 

그러므로 복제 지연이 발생한다는 가정 하에 아래와 같은 현상이 발생할 수 있다.

1. RW에 레코드 생성

2. 복제 지연 기간 내 RO에서 1번에서 생성된 레코드 조회(findById) → NOT_FOUND

 

결론

  • findById()는 호출자 상위에서 별도의 트랜잭션이 존재하지 않는다면 readOnly 트랜잭션을 생성하여 조회
  • RW/RO를 분리하여 사용하고 있다면 복제 지연으로 인하여 RW에서 생성 한 레코드를 findById()로 조회하였을 때 NOT_FOUND를 응답받을 수 있음

해결 방안

  • findById() 호출자에서 트랜잭션(readOnly = false)을 생성하여 RW에서 조회
  • Repository에 Custom Method를 정의하여 사용(RW로 접근)