[JPA] @Transaction(readOnly=true) 성능 향상 이유?
개요
스프링 프레임워크에서 어노테이션으로 트랜잭션을 읽기 전용 모드로 설정할 수 있다.
@Transactional(readOnly = true)
예상치 못한 엔티티의 등록, 변경, 삭제를 예방할 수 있고, 또한 성능을 최적화할 수 있습니다.
하지만 왜?? 성능을 최적화 할 수 있는지는 알지 못했습니다. 그래서 정리해본 글입니다.
읽기 전용 쿼리의 성능 최적화
엔티티가 영속성 컨텍스트에 관리되면 1차 캐시부터 변경 감지까지 얻을 수 있는 혜택이 많다.
하지만 영속성 컨텍스트는 변경 감지를 위해서 스냅샷 인스턴스를 보관하므로 더 많은 메모리를 사용하는 단점이 존재한다.
혹시 영속성 컨텍스트와 변경 감지가 동작하는 원리에 대한 정보는 아래 글을 참고해주세요.
만약 조회만 하는 경우에 읽기 전용으로 엔티티를 조회하면 메모리 사용량을 최적화할 수 있다.
읽기 전용으로 엔티티를 조회하는 방법
그러면 읽기 전용으로 엔티티를 조회하는 방법에는 어떤 방법이 있을까?
1. 스칼라 타입으로 조회
먼저, 첫번째 방법은 엔티티가 아닌 스칼라 타입으로 필요한 필드를 조회하는 것이다.
엔티티 객체가 아니므로 영속성 컨텍스트가 결과를 관리하지 않는다.
select o.id, o.name from Order p
2. 읽기 전용 쿼리 힌트 사용
하이버네이트 전용 힌트인 org.hibernate.readOnly를 사용하면 엔티티를 읽기 전용으로 조회할 수 있다.
읽기 전용이므로 영속성 컨텍스트는 스냅샷을 보관하지 않는다. 따라서 메모리 사용량을 최적화할 수 있다.
즉 엔티티를 읽기 전용으로 조회해서 메모리를 절약한다.
3. 읽기 전용 트랜잭션 사용
스프링 프레임워크에서 제공하는 트랜잭션을 읽기 전용 모드를 설정할 수 있다.
@Transactional(readOnly = true)
트랜잭션에 readOnly=true 옵션을 주면 스프링 프레임워크가 하이버네이트 세션 플러시 모드를 MANUAL로 설정한다.
이렇게 하면 강제로 플러시를 호출하지 않는 한 플러시가 일어나지 않는다.
따라서 트랜잭션을 커밋하더라도 영속성 컨텍스트가 플러시 되지 않아서 엔티티의 등록, 수정, 삭제이 동작하지 않고,
또한 읽기 전용으로, 영속성 컨텍스트는 변경 감지를 위한 스냅샷을 보관하지 않으므로 성능이 향상된다.
엔티티를 읽기 전용으로 조회하면, 변경 감지를 위한 스냅샷을 유지하지 않아도 되고, 영속성 컨텍스트를 플러시 하지 않아도 돼 성능을 최적화할 수 있다.