이전에 step2에서 포인트컷 표현식과 트랜잭션 속성을 이용해 트랜잭션을 일괄적으로 적용하는 방식은 복잡한 트랜잭션 속성이 요구되지 않는 한 대부분의 상황에 적용가능하지만 클래스나 메소드에 다라 제각각 속성이 다른, 세밀하게 튜닝된 트랜잭션 속성을 적용해야 하는 경우 일괄적으로 속성을 부여하는 것 대신에 직접 타깃에 트랜잭션 속성정보를 가진 애노테이션을 이용하는 방법이 있다.
@Transactional을 정의한 코드는 직관적이라 이전에 설명한 속성을 모두 포함하고 있다.
pacakage org.springframwork.transaction.annotation;
...
@Target({ElementType.METHOD, ElementType.TYPE})
@Retension(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Transactional {
String value() default "";
Propagation propagation() default Propagaion.REQUIRED;
Isolation isolation() default Isolation.DEFAULT;
int timeout() default TransactionDefinition.TIMEOUT_DEFAULT;
boolean readOnly() defalut false;
Class<? extends Throwable>[] rollbackFor() default {};
String[] rollbackForClassName() default {};
Class<? extends Throwable>[] noRollbackFor() default {};
String[] noRollbackForClassName() default {};
}
@Transactional 애노테이션의 타깃은 메소드와 타입이다. 따라서 메소드, 클래스, 인터페이스에 사용가능하다. @Transactional 애노테이션을 트랜잭션 속성정보로 사용하도록 지정하면 @Transactional이 부여된 모든 오브젝트를 자동으로 타깃 오브젝트로 인식한다. 이 때 사용되는 포인트컷은 TransactionAttributeSourcePointcut이다. TransactionAttributeSourcePointcut은 스스로 표현식과 같은 선정기준을 가지고 있지 않고 이 애노테이션이 붙은 오브젝트를 모두 찾아서 포인트컷의 선정 결과로 돌려준다.
@Transactional을 이용한 트랜잭션 속성을 사용하는 것은 스프링이 모든 설정을 하나의 태그에 담아뒀기 때문에 필요한 어드바이저, 어드바이스, 포인트컷, 애노테이션을 이용하는 트랜잭션 속성 정보가 등록된다.
<tx:annotation-driven/>
@Transactional의 경우 메소드 레벨이 가장 큰 우선순위를 가지기 때문에 기본적으로 Service 단에서 작업할 경우 클래스 레벨에 @Transactional(readOnly=true)를 지정하고 데이터 처리작업에 @Transactional을 새로 정의해서 쓰는 것이 효율적인 방법이라고 볼 수 있다.
@Transactional(readOnly=true)
public interface UserService {
@Transactional
void add(User user);
@Transactional
void delete(User user);
User get(String id);
List<User> getAll();
}
반대로 클래스레벨에 @Transactional를 지정해줬으면 읽기 전용에 따로 readOnly=true 속성을 적용해주어도 상관없다.
일부 메소드에만 트랜잭션이 필요하다면 메소드 레벨에 @Transactional을 적용하면 된다. 반면에 대부분의 메소드에서 트랜잭션이 필요하다면 클래스에 @Transactional을 지정하는 것이 편리하다. 그런 경우 굳이 트랜잭션이 필요없는 메소드는 어떻게 해야할까? @NotTransactional이 기존에 존재했지만 스프링 3.0에서 제거대상이기 때문에 전파 속성을 이용하는 방법이 있다. 다음과 같이 NAVER 전파 속성을 지정해주면 트랜잭션이 시작하지 않을 것이다.
@Transactional(propagation=Propagation.NEVER)
추가적으로 테스트 메소드나 클래스에서 사용하는 @Transactional은 애플리케이션의 클래스에 적용할 때와 디폴트 속성은 동일하지만 중요한 차이점이 하나 있는데 테스트용 트랜잭션은 테스트가 끝나면 자동으로 롤백이 된다는 것이다. 원하지 않을 경우 @Rollback(false) 옵션을 메소드 레벨에 추가하거나 클래스 레벨에 @TransactionConfiguration(defaultRollback=false)를 추가해주어도 된다. 이는 롤백 여부에 대한 기본 설정과 트랜잭션 매니저 빈 등의 설정을 지정하는데 사용할 수 있다. 기본값은 transactionManager를 사용한다.
참고 자료 - 토비의 스프링 3.1 | 저자 이일민
'IT' 카테고리의 다른 글
JAVA 불필요한 객체 생성 (1) | 2023.06.11 |
---|---|
JPA N+1 문제 1분 이해하기 (0) | 2023.06.01 |
스프링 AOP(Aspect Oriented Programming) step2 : 네임스페이스 (0) | 2023.05.09 |
스프링 트랜잭션 (Spring Transaction) step5 : 빈 후처리기 DefaultAdvisorAutoProxyCreator (0) | 2023.05.05 |
스프링 AOP(Aspect Oriented Programming) step1 (0) | 2023.05.05 |