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로 접근)
'자바 개발자되기' 카테고리의 다른 글
Inner Class에 대한 유효성 검사(javax.validation) (0) | 2022.07.02 |
---|---|
Java NIO - SocketChannel non-blocking mode에서 Read Timeout 설정 (0) | 2021.11.02 |
@MockBean Spring Context Recreated (0) | 2021.05.24 |
구체적인 Exception Catch를 해야하는 이유 (0) | 2021.04.22 |
Open Session In View와 트랜잭션, 그리고 영속성 컨텍스트 (0) | 2021.03.24 |