트랜잭션을 유지하기 위해서는 데이터베이스와의 연결인 커넥션이 필요합니다. 트랜잭션을 시작 전 커넥션을 얻은 후 트랜잭션을 시작하고, 커밋 전 동일한 커넥션을 사용하여 트랜잭션을 커밋하여야 합니다. 트랜잭션 매니저는 이를 ThreadLocal 을 사용하여 동일한 Thread 에서 같은 커넥션을 사용할 수 있도록 지원합니다.
동작 순서
출처 - 인프런/김영한님 스프링 DB 1편 강의
1. 트랜잭션 필요시, 트랜잭션 매니저로 트랜잭션 시작 요청 2. Datasource 를 사용하여 커넥션을 획득한 후, auto commit 을 해제한 뒤 트랜잭션을 시작한다. 3. 해당 커넥션을 동기화 매니저에 요청하여 ThreadLocal 에 저장한다.
출처 - 인프런/김영한님 스프링 DB 1편 강의
3. 내부 로직에서 트랜잭션이 필요한 경우, 트랜잭션 동기화 매니저를 통해 커넥션을 획득하여 SQL 을 실행한다. (Spring data 사용시, Repository 내부 로직에서 진행됩니다.)
출처 - 인프런/김영한님 스프링 DB 1편 강의
4. 트랜잭션 종료나 롤백이 필요한 경우 트랜잭션 매니저에 요청합니다. 5. 트랜잭션 매니저는 커넥션을 동기화 매니저로부터 얻은 후, 종료나 롤백을 호출한 뒤 동기화 매니저의 Thread Local 을 정리하고, auto commit 을 true 로 되돌린 후, 커넥션을 해제하거나 풀로 되돌립니다.
@Transactional
스프링의 트랜잭션 추상화 기술로 트랜잭션을 쉽게 관리할 수 있었지만, 비즈니스 로직에 해당 로직이 중복된다는 점이 문제가 되었습니다. 이를 해결하기 위해 스프링에서는 AOP 기반의 @Transactional 을 지원하여 트랜잭션 코드를 비즈니스 로직에서 제거할 수 있었습니다.
주요 속성
readonly = true / false(기본)
트랜잭션을 읽기 전용 트랜잭션으로 사용할 것인지 설정합니다. 기본적으로 해당 옵션을 사용하게 되면, 트랜잭션 내부에 RUD 관련 SQL 이 존재할 경우, 예외가 발생하게 됩니다. 하지만 일부 구현체의 경우 예외가 발생하지 않고 해당 쿼리가 무시될 수 있습니다. 트랜잭션 내부에서 읽기 작업만 진행되어 성능 최적화 가능성이 존재할 경우 사용합니다.
propagation
@Transactional 이 적용된 메서드 간 호출한 메서드의 트랜잭션과 호출된 메서드의 트랜잭션의 관계를 설정하는 옵션입니다.
@Transactional 은 AOP 를 활용한 기술로, 메서드 단위로 적용됩니다. 즉, 2개 이상의 메서드를 사용시 스프링에서는 이를 구분하여 처리하게 됩니다. 이 때, 각 상황에 따라 각 메서드가 모두 하나의 트랜잭션을 통해 원자적으로 실행되어야 하는지, 아니면 모두 독립된 트랜잭션으로 실행해야 하는지 등 을 결정하고, 구현해야 합니다. 스프링에서는 이를 전파 속성을 통해 지원합니다.
REQUIRED - 기본
기존 트랜잭션이 있다면 해당 트랜잭션을 사용하고, 없다면 새로 생성하여 사용합니다.
REQUIRES_NEW
매번 새로운 트랜잭션을 사용하며, 기존의 트랜잭션은 잠시 중단됩니다.
SUPPORTS
기존 트랜잭션이 있다면 해당 트랜잭션을 사용하고, 없다면 트랜잭션 없이 실행합니다.
NOT_SUPPORTED
기존 트랜잭션이 있다면 잠시 중단하고, 트랜잭션 없이 실행합니다.
MANDATORY
기존 트랜잭션에서 실행하며, 없다면 예외를 발생시킵니다.
NEVER
기존 트랜잭션이 있다면 예외를 발생시키고, 없다면 트랜잭션 없이 실행합니다.
NESTED
현재 트랜잭션이 있다면 중첩 트랜잭션을 시작하고, 없다면 새로 생성하여 사용합니다. 이 때, 자식 트랜잭션은 부모 트랜잭션의 영향을 받지만, 부모 트랜잭션은 자식 트랜잭션의 영향을 받지 않습니다. 즉, 자식 트랜잭션에서 롤백시 부모 트랜잭션은 커밋되고, 부모 트랜잭션에서 롤백시 자식 트랜잭션도 롤백 됩니다.
rollbackFor = {XXX.class}
해당 트랜잭션이 어느 예외가 발생했을 때 롤백시킬 것인지를 설정하는 옵션입니다. 기본적으로 RuntimeException(UncheckedException) 혹은 Error 에서 발생합니다. 이는 runtimeException 의 경우 비즈니스 로직 상의 문제로 발생하며, 기본적으로 문제 상황이 복구되지 않을 것이라는 이유 때문인 것으로 보이며, Error 의 경우에도 복구 가능성이 없기 때문으로 보입니다.
timeout
해당 트랜잭션이 완료되어야 하는 시간을 설정하는 옵션이며, 해당 시간이 초과된다면 롤백 후 예외가 발생합니다.