트랜잭션을 적용할 때 DB에 쓰기 작업이 없을 때 readOnly
옵션을 true로 설정하는 경우가 많습니다. MySQL에서 이 옵션을 사용하면 얻는 이점이 궁금해 글을 쓰고자 합니다. (그런데 잡담이 더 많아진..)
트랜잭션은 작업 수행의 가장 작은 논리적인 단위입니다. 또한 데이터베이스에서 작업의 완전성을 보장해줍니다. 트랜잭션은 ACID 라는 특징을 가지고 있는데 간단하게 정리하겠습니다.
스프링 프레임워크에서는 트랜잭션을 @Transactional
애노테이션을 통해 지원하고 있습니다.
@Transactional
은 메서드 혹은 클래스 레벨에 적용될 수 있으며 해당 메서드에서 수행되는 모든 데이터베이스 관련 작업을 하나의 트랜잭션으로 처리하게 됩니다.
@Transactional
은 메서드가 실행되는 동안 하나의 트랜잭션을 생성하고 해당 메서드가 완료되면 커밋(commit)을 수행하게 됩니다. 하지만 메서드가 실행 도중 예외(UncheckedException)을 던지면 트랜잭션은 롤백(rollback)됩니다.
의문점 : 왜 스프링은 UncheckedException이 발생했을 때 기본적으로 롤백하도록 했을까?
생각 : CheckedException은 예외처리를 강제하기 때문에 롤백하지 않고 UncheckedException은 예상하지 못한 예외이기 때문에 롤백하지 않을까?
물론 @Transactional의
rollbackFor
,noRollbackFor
속성을 통해 롤백할 예외를 지정할 수 있습니다. 또한rollbackForClassName
이나noRollbackForClassName
속성을 통해 예외 클래스 이름으로도 지정할 수 있습니다.
이러한 스프링의 @Transactional
은 다양한 옵션을 가지고 있습니다.
이 중 readOnly 옵션을 사용하면 왜 성능이 향상되는지 알아보고자 합니다.
더 나은 안정성: 읽기 전용 트랜잭션은 데이터를 변경하지 않으므로 예기치 않은 결과가 발생할 가능성이 줄어듭니다. 이로 인해 애플리케이션의 안정성이 높아질 수 있습니다. 스프링에서 @Transactional(readOnly = true)
옵션을 사용했을 때 해당 트랜잭션에서 데이터가 변경된다면 TransactionRequiredException
이 발생합니다.
더 나은 가용성: 읽기 전용 트랜잭션은 더 빠르게 완료될 수 있으므로 애플리케이션의 가용성이 높아질 수 있습니다. 또한, 다른 트랜잭션과 충돌하지 않으므로 더 많은 클라이언트 요청을 동시에 처리할 수 있습니다.
위 두 개는 공통적입니다. 성능 향상의 이유는 DBMS마다 동작방식이 다른데 이 중 MySQL을 기준으로 알아보고자 합니다.
MySQL InnoDB에서는 읽기 전용 트랜잭션에 대하여 불필요한 트랜잭션 ID를 부여하지 않아도 되기 때문에 오버헤드가 발생하지 않아 성능의 이점을 얻을 수 있습니다.
트랜잭션 ID는 쓰기 작업이나 SELECT ... FOR UPDATE
같은 locking read
작업을 수행할 때 부여됩니다. 이런 불필요한 트랜잭션 ID 부여 작업을 제거하면 쿼리 혹은 데이터 변경문이 read view
를 구성할 때마다 참조되는 내부 데이터 크기를 줄이게 됩니다.
read view?
InnoDB의 MVCC에 의해 사용되는 내부 스냅샷
@Transacational
을 통해 트랜잭션을 지원합니다.readOnly=true
는 읽기 전용 트랜잭션을 지원합니다.https://www.geeksforgeeks.org/acid-properties-in-dbms/
https://dev.mysql.com/doc/refman/8.0/en/glossary.html#glos_acid
https://dev.mysql.com/doc/refman/8.0/en/innodb-performance-ro-txn.html
많이 배우고 갑니다 교수님 👀