@Transactional과 @Transactional(readOnly = true) 차이
우아한테크코스

@Transactional과 @Transactional(readOnly = true) 차이

서론

지하철 노선도 미션에서 리뷰어에게 다음과 같은 피드백을 받았습니다.

@Transactional과 @Transactional(readOnly = true)은 어떻게 다른지, 왜 사용했는지 공유해주실 수 있나요~?

그에 대한 저의 답변입니다.

  1. @Transactional(readOnly = true)을 사용한 이유는 명령쿼리분리원칙 때문입니다. 조회 쿼리만을 사용하는 메서드에는 readOnly = true을 붙여 상태를 변경시키는 행위(생성,수정,삭제)를 금지할 수 있습니다.
  2. 또한, readOnly = true가 메서드에 붙어있다면, 다른사람이 보기에 이 메서드는 상태를 변경시키지 않는 쿼리라고 생각할테니 프로그램의 안정성에 기여할 것이라는 생각을 했었습니다.
  3. readOnly=true를 사용함으로써 얻을 수 있는 또다른 장점은 성능이 향상된다는 것입니다. 이것이 어떻게 성능을 향상시키는지는 좀 더 찾아봐야겠네요.

이 답변은 100% 맞다고 장담할 수 없습니다. 왜냐하면 (readOnly = true)는 write 연산을 무조건 막아주지 않기 때문입니다.


본론

readOnly = true 가 내부적으로 어떻게 동작하는지 궁금해 java doc을 살펴보았습니다.

이 내용을 다시 요약해보았습니다.

  1. readOnly=true는 트랜잭션이 효과적으로 read-Only일 경우 붙일 수 있다.
  2. 런타임시 트랜잭션 최적화를 해준다.
  3. Default값은 false이다.
  4. 이것은 실제 트랜잭션 시스템에 힌트 역할을 수행한다. 그래서 쓰기 연산시도를 완전히 막아주진 못한다.
  5. 이 힌트를 이해할 수 없는 트랜잭션 매니저라면 예외를 발생시키지 않을 뿐더러 오히려 무시한다.

제가 알고 있었던 지식과 달랐던 점은 쓰기연산을 완전히 막아주지 못한다 였습니다. read-Only 속성은 JDBC 제조사 별로 다르게 지원됩니다. Oracle Driver은 이전부터 지원해왔고, Mysql은 5.6.5 이상의 버전이 되어서야 지원하게 되었습니다. 그리고 H2에서는 read-Only 속성을 지원하지 않습니다. H2관련링크

 

하이버네이트를 사용하는 경우에는 Session의 FlushMode를 Manual로 변경합니다. Dirty checking을 생략하기 때문에 성능 향상의 이점을 얻을 수 있습니다.


H2 테스트

h2 인메모리 DB 를 사용할때는 read-only 속성의 트랜잭션 안에서 update 를 실행해도 예외가 발생하지 않는지 직접 테스트해봤습니다.

Jdbc를 이용해 update 쿼리를 날리는 메서드에서 readOnly=true 속성을 붙여 실험해보았습니다.

    @Transactional(readOnly = true)
    public void updateLine(Long id, String name, String color) {
        checkExistLine(id);
        lineDao.updateById(id, name, color);
    }

그 결과 어떠한 예외도 발생하지 않고 정상적으로 응답되었습니다.

###### HTTP Request ######
PUT /lines/30 HTTP/1.1
accept: */*
content-type: application/json
content-length: 73
host: localhost:49998
connection: Keep-Alive
user-agent: Apache-HttpClient/4.5.13 (Java/11.0.11)
accept-encoding: gzip,deflate


###### HTTP Response ######
HTTP/1.1 200 OK
Keep-Alive: timeout=60
Connection: keep-alive
Vary: Origin
Content-Length: 0
Date: Tue, 10 May 2022 02:05:45 GMT

이를 통해 read-only 속성을 이해할 수 없는 트랜잭션 매니저는 예외를 발생시키지 않고 무시한다는 것이 사실임을 알 수 있었습니다.


참고문서

https://kwonnam.pe.kr/wiki/springframework/transaction#read_only
https://junhyunny.github.io/spring-boot/jpa/junit/transactional-readonly/