@Transactional
어노테이션은 메서드에 트랜잭션을 만들어 준다. 여러가지 속성을 설정할 수 있는데 읽기 전용 트랜잭션, 전파 레벨, 격리 레벨, 타임 아웃, 롤백 규칙 등을 설정해줄 수 있다.
Spring 에서 전파와 격리 레벨에 대해서 알아보자.
트랜잭션이 진행중일 때 추가되는 트랜잭션을 어떻게 처리할지 결정하는 방법을 뜻한다.
Default 설정이며 실행중인 트랜잭션이 있으면 추가되고, 없으면 새로운 트랜잭션을 만든다.
실행중인 트랜잭션이 있으면 추가되고, 없으면 트랜잭션 없이 실행된다.
실행중인 트랜잭션이 있으면 추가되고, 없으면 Exception을 반환한다.
실행중인 트랜잭션이 있으면 Exception을 반환하고, 없으면 트랜잭션 없이 실행된다.
실행중인 트랜잭션이 있으면 잠시 보류시킨 후 트랜잭션 없이 실행하고, 없으면 트랜잭션 없이 실행된다.
실행중인 트랜잭션이 있으면 잠시 보류시킨 후 새로운 트랜잭션을 만들고, 없으면 새로운 트랜잭션을 만든다.
실행중인 트랜잭션이 있으면 Point를 만들고(에러 발생시 Point로 Rollback된다.), 없으면 새로운 트랜잭션을 만든다.
그렇다면 스프링에선 어떻게 관리되고 있는 것일까? 코드와 함께 알아보자.
Spring에서 @Transactional
을 사용하는 경우 TransactionManager
인터페이스를 상속받는 PlatformTransactionManager
가 있다. PlatformTransactionManager
는 Spring 트랜잭션의 필수 인터페이스라고 설명이 되어있다.
본인은 JPA를 사용했기 때문에 PlatformTransactionManager
를 상속받는 AbstractPlatformTransactionManager
를 상속받은 JPATransactionManager
를 사용한다.
JPATransactionManager
의 메서드를 모두 살펴보았지만 TransactionDefinition외에 Propagation, Isolation에 대한 내용이 없었다. 그래서 AbstractPlatformTransactionManager
를 살펴보았다.
트랜잭션이 있는 경우 handlerExistingTransation 메소드를 호출한다.
그렇지 않은 경우 TIME OUT 여부를 확인하고, Propagation 레벨에 대해서 처리한다.
위에 적은 것 처럼 NEVER인 경우 IllegalTransactionStateException을 반환하고 다른 레벨에 대해서 적절히 처리하는 모습이다.
트랜잭션이 동시에 수행될때 다른 트랜잭션이 동일한 데이터에 대해서 어떻게 할 수 있는지에 대한 격리 레벨을 뜻한다.
참고
Default는 DBMS의 isolation level을 따라간다.
Mysql은 REPEATABLE READ가 기본 설정이다.
그외 대부분의 DBMS는 READ_COMMIT이 기본 설정이다.
트랜잭션의 Commit, Rollback 여부에 상관없이 다른 트랜잭션이 값을 조회할 수 있다.
Dirty Read, Non-Repeatable Read, Phantom Read 현상이 모두 발생한다.
Commit한 데이터는 읽을 수 있다.
Dirty Read 현상은 일어나지 않지만, Non-Repeatable Read 현상과 Phantom Read 현상이 발생한다.
트랜잭션에 ID를 부여하여 조회하려는 트랜잭션 ID보다 작은 트랜잭션에서 변경한 내용만 읽는다.
Dirty Read, Non-Repeatable 현상이 일어나지 않지만, Phantom Read현상이 발생한다.
모든 트랜잭션을 순차적으로 수행하는 방법이다. 동시성 문제는 없지만, 성능이 매우 떨어지게 된다.
위의 내용이 자세히 이해가 안될수 있다. 여기에 그림과 함께 정리해둬서 보기 좋으니 참고하길 바란다.
Isolation Level은 AbstractPlatformTransactionManager
의 getTransaction 메서드에서 TransactionDefinition 객체에 담겨 startTransaction 메서드에 전달된다.
위에서 언급한 handleExistingTransaction 메서드의 하단 부분이다.
isValidateExistingTransaction은 Transaction Isolation 속성을 무시하는 flag이고 true인 경우 Default 설정으로 적용된다.
currentIsolationLevel이 null이거나 호환하지 않는 경우 에러를 반환한다.