- Published on
조회만 하는 경우 @Transactional이 필요할까?
- Authors
- Name
- ywj9811
@Transactional 과 @Transactional(readOnly=true)
위의 두개가 존재한다는 사실과 기본적인 차이점은 대부분이 알고 있다.
적당히 다시 한번 살피고 넘어가자
@Transactional
이것은 어노테이션을 통한 선언적 트랜잭션으로 클래스 혹은 메소드에 트랜잭션이 적용된 프록시 객체를 생성해주며, 이를 통해 트랜잭션을 적용시켜 Commit 혹은 Rollback을 수행한다.@Transactional(readOnly=true)
이것은 속성이 적용되지 않은 트랜잭션과 다르게, JPA 세션 플래시 모드를 MANUAL로 설정한다.
@Transactional(readOnly=true) 는 왜 사용할까
습관적으로 사용하던 도중, 순간 조회만 하는 경우 그럼 @Transactional
자체를 넣지 않으면 되지 않는가? 라는 생각이 들었다.
굳이 readOnly라는 속성을 사용하는 이유가 무엇일까.
@Transactional을 사용하는 이유는 무엇일까
우선, 근본적으로 @Transactional
을 사용하는 이유는 무엇일까.
스프링 컨테이너는 트랜잭션 범위의 영속성 컨텍스트 전략을 기본으로 사용하고 있다.
이는 트랜잭션을 시작할 때 영속성 컨텍스트를 시작하고, 트랜잭션이 종료될 때 영속성 컨텍스트가 종료된다는 뜻이다.
그리고, 같은 트랜잭션 안에서는 항상 같은 영속성 컨텍스트에 접근한다.
따라서 @Transactional
없이 지연 로딩을 사용하게 된다면 LazyInitializationException
이 발생할 수도 있다.
또한, 더티체킹 등등과 같은 이유로 비즈니스 로직에는 @Transactional
을 사용하게 된다.
OSIV?
OSIV가 무엇인가? Open Session In View 의 약자로, HTTP 요청마다 API 응답이 끝날 때 까지 영속성 컨텍스트와 데이터베이스 컨넥션을 유지하는 것이다.
이를 통해 @Transactional
없이 지연로딩을 사용할 수 있게 된다.
하지만, OSIV를 false로 변경하게 되면 위에서 말한 예외가 발생하게 된다.
@Transactional(readOnly=true)는 왜 사용할까
그럼 OSIV에 대한 설정도 하지 않았고, 조회만 하는 로직이라면 정말 @Transactional
이 필요 없지 않을까?
틀린 말은 아니라고 생각한다.
하지만, 아마 동시성 이슈를 생각하지 않아도 되는 단순 조회만 하는 서비스 계층은 많이 없을 것이고 확장성과 유지보수성을 생각하면 @Transactional(readOnly=true)
는 넣어주는 것이 좋다고 생각한다.
왜냐하면 트랜잭션 자체를 삭제하는 것과 @Transactional(readOnly=true)
모두 영속성 컨텍스트를 플러시 하지 않기 때문에 스냅샷 비교와 같은 무거운 동작은 하지 않아서 성능이 향상될 수 있고, 트랜잭션 자체를 삭제해서 트랜잭션에 대한 과정이 사라지는 것에서 오는 성능 향상은 매우 미비할 것이기 때문이다.
또한 @Scheduled
와 같이 내부에서 동작하는 경우 HTTP 요청이 아니기 때문에 OSIV가 동작하지 않아서 지연로딩을 사용하는 경우 위에서 언급한 예외가 발생하게 된다.
따라서 이 또한 Transactional(readOnly=true)
를 사용하는 것이 좋은 이유가 되기도 한다.
휴먼 에러를 미리 방지하는 것이 좋지 않을까.
@Transactional(readOnly=true)의 성능 향상
트랜잭션을 읽기 전용으로 설정하게 되면 해당 메소드가 데이터를 읽기만 한다는 것을 DB에 알려줘 쿼리 및 캐싱을 최적화 할 수 있다고 한다.
또한 위에서 언급한 것과 같이 플러시를 수행하지 않기 때문에 스냅샷 저장과 같은 무거운 동작을 하지 않는 것 또한 이유가 되기도 한다.