[JPA] @Transactional(readOnly = true)의 효과와 사용 시 주의할 점

2023. 3. 12. 15:57·Java/Spring

기존 프로젝트에서 @Transactional으로 설정해 준 서비스에 readOnly 속성을 사용하지 않고 있었는데 데이터를 읽기만 하는 서비스에 readOnly = true를 적용해 읽기 전용 모드로 설정해 주는 것이 좋을 것 같다는 이야기를 듣고 읽기 전용으로 설정해 주면 어떤 효과를 얻을 수 있는지 알아봤다.

@Transactional(readOnly = true)


Spring에서 @Transactional 어노테이션을 사용할 수 있는데 트랜잭션을 readOnly = true로 설정해 주면 읽기 전용 모드로 변경할 수 있다. 그러면 @Transactional(readOnly = true) 속성을 적용함으로써 얻을 수 있는 이점에 대해 알아보자.

 

우선 @Transactional(readOnly = true)은 DB에서 데이터를 읽기만 하는 서비스 메서드에 적용을 해야 한다. readOnly에서도 알 수 있듯이 읽기 전용으로 변경하는 것이기 때문에 데이터를 수정하는 서비스에 적용하면 안된다.

 

성능 최적화

트랜잭션을 읽기 전용으로 설정하면 해당 메서드가 데이터를 읽기만 한다는 것을 DB에 알려줌으로써 쿼리 및 캐싱을 최적화할 수 있다.

그리고 읽기 전용으로 설정하면 데이터 변경이 일어나지 않기 때문에 변경감지를 위한 스냅샷을 저장하는 동작 또한 하지 않기 때문에 성능이 향상되는 것을 기대할 수 있다.

 

데이터 일관성

일반적으로 트랜잭션을 사용해서 DB에서 데이터의 일관성과 무결성을 보장하는 데 사용하는데 트랜잭션을 읽기 전용으로 설정하면 실수로 데이터를 수정해서 일관성을 위반할 가능성이 낮아진다.

 

가독성 향상

코드를 작성하는 개발자는 @Transactional(readOnly=true)이 설정된 메서드가 DB에서 데이터를 읽기만 한다는 것을 명확하게 확인할 수 있다. 이로 인해 코드의 가독성이 향상이 된다.

 

 

@Transactional(readOnly=true)을 사용할 때 고려해야 할 점


읽기 작업만 하는 모든 메서드에 @Transactional(readOnly=true)을 무지성으로 사용해서는 안된다.  

 

readOnly = true를 적용할 때 Optimistic Lock의 동작에 영향을 미칠 수 있다는 것을 고려해야 한다.

JPA의 동시성 제어에 접근 방식이 두 가지 존재하는데 그중 하나가 Optimistic Lock이고 또 다른 하나가 Pessimistic Lock이다.

 

Optimistic Lock이란? 

낙관적 락(Optimistic Lock)은 두 개의 트랜잭션이 동시에 동일한 데이터를 수정하려고 시도할 때 발생하는 충돌을 방지하는 데 사용되는 메커니즘인데, 트랜잭션의 대부분은 충돌이 발생하지 않는다고 낙관적으로 가정하는 방법이다.

 

낙관적 락을 사용하려면 Entity에 @Version 어노테이션을 추가해서 사용할 수 있다. 

 

@Entity
public class Post {
    @GeneratedValue
    @Id
    private Long id;

    @Version
    private Long version;
    
    // Constructor, Getter ...
}

 

@Version 어노테이션을 추가하면 이제 트랜잭션이 엔티티를 수정할 때마다, 현재 버전 번호가 자동으로 업데이트되며 기록이 된다. 다른 트랜잭션이 동일한 엔티티를 수정하려고 시도하면 버전 번호를 확인하는데 이때 첫 번째 트랜잭션이 수정을 했다고 가정하면 두 번째 트랜잭션의 버전 번호는 조회한 시점의 버전과 수정한 시점의 버전이 다르다는 것을 확인한다. 이때 충돌이 발생했다는 것을 두 번째 트랜잭션에 알리게 된다.

 

즉, 데이터를 조회한 시점의 버전과 수정하려고 할 때 버전이 일치하지 않으면 충돌이 발생한 것으로 간주하고 예외가 발생한다.

 

@Transactional(readOnly=true)를 사용하면 이러한 낙관적 락 동작에 영향을 미치게 된다.

만일 @Transactional(readOnly=true)로 설정한 메서드에 엔티티를 수정하는 로직이 있을 경우, 해당 트랜잭션이 엔티티를 수정하는 것이 아니라 읽기 전용으로 설정했기 때문에 버전 번호를 확인하지 못할 수 있다. 이때 충돌을 감지하지 못하고 동시에 발생한 트랜잭션의 변경 사항을 덮어쓰게 되어 데이터 불일치 문제가 발생할 수 있다.

 

예를 들어 트랜잭션이 엔터티를 읽고 수정한 뒤, 다른 트랜잭션이 수정하려고 시도하는 경우 낙관적 락 충돌을 감지하지 않고, 수정된 엔터티는 DB에 저장되어 다른 동시 트랜잭션의 변경 사항을 덮어쓰게 된다.

 

그래서 낙관적 락이 활성화된 엔티티는 @Transactional(readOnly=true)로 설정된 메서드에서 엔티티를 읽기 작업만 하도록 하고, 수정하지 않도록 조심해야 한다.

 

정리

정리하면 @Transactional(readOnly=true)를 사용하면 해당 트랜잭션이 데이터를 읽기만 하도록 설정하여 애플리케이션의 데이터 일관성과 성능을 향상할 수 있다. 

'Java > Spring' 카테고리의 다른 글

[Spring] Spring Servlet과 Servlet Container란? (DispatcherServlet)  (0) 2023.07.02
[Spring] 의존성 주입 (Dependency Injection, DI) 3가지 방법  (0) 2023.01.23
[Spring] 스프링 싱글톤  (0) 2023.01.22
싱글톤 패턴(Singleton)의 사용 이유와 문제점  (0) 2023.01.21
[JPA] OSIV(Open-Session-In-View)와 지연로딩에 대해서  (0) 2023.01.15
'Java/Spring' 카테고리의 다른 글
  • [Spring] Spring Servlet과 Servlet Container란? (DispatcherServlet)
  • [Spring] 의존성 주입 (Dependency Injection, DI) 3가지 방법
  • [Spring] 스프링 싱글톤
  • 싱글톤 패턴(Singleton)의 사용 이유와 문제점
seungjjun
seungjjun
  • seungjjun
    개발이야기
    seungjjun
  • 전체
    오늘
    어제
    • 분류 전체보기
      • 성장이야기
        • TIL
        • 주간회고
      • Java
        • Spring
        • Spring Security
      • 트러블슈팅
      • Kafka
      • OS
      • Network
      • 메가테라
      • Database
      • Algorithm
      • Git
      • HTML
      • CSS
      • 독서
      • 컴퓨터 이해하기
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    항해99
    이커머스 프로젝트
    개발일지
    메가테라 주간회고
    메가테라
    graphQL
    redis
    항해플러스
    주간회고
    Til
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
seungjjun
[JPA] @Transactional(readOnly = true)의 효과와 사용 시 주의할 점
상단으로

티스토리툴바