이전에 봤던 XML 설정을 사용하여 트랜잭션을 선언하는 방법 말고 어노테이션을 사용하여 설정하는 방법을 설명합니다.

@Transactional
public class DefaultFooService implements FooService {

    Foo getFoo(String fooName);

    Foo getFoo(String fooName, String barName);

    void insertFoo(Foo foo);

    void updateFoo(Foo foo);
}

@Tracsactional 어노테이션은 인터페이스 선언, 클래스 선언, public 메소드 선언 위에 붙일 수 있습니다. 그리고 XML 설정파일에는 다음의 한 줄만 추가하면 건드릴 것이 없습니다.

<tx:annotation-driven transaction-manager="txManager"/>

물론 txManager는 등록되어 있어야겠죠.[footnote]이전에 살펴봤지만 transactionManager라는 이름으로 등록되어 있다면 굳이 명시적으로 tracsaction-manger 라는 속성을 사용하지 않도 알아서 찾게 됩니다.[/footnote]

이 어노테이션을 인터페이스에도 붙일 수 있다고 했지만 그건 인터페이스 기반의 프록시만 사용하겠다는 가정하에 이루어지기 때문에 모든 클래스에 붙이는 것을 권장합니다.

이유는? - The fact that annotations are not inherited means that if you are using class-based proxies then the transaction settings will not be recognised by the class-based proxying infrastructure and the object will not be wrapped in a transactional proxy (which would be decidedly bad).

이렇다고 합니다. 사실 뭔 말인지 잘 몰라서 걍 붙여 논건데요. 나중에 이해가 되면 한글로 바꾸겠습니다. Anyway 결론은 '트랜잭션 처리가 되어야 할 모든 클래스에 @Transactional을 붙여라.' 입니다.

<tx:annotation-driven/> 의 속성들

Attribute

Required?

Default

Description

transaction-manager

No

transactionManager

●Transaction Manager bean의 이름

proxy-target-class

No

 

생성할 프록시의 종류를 나타냅니다.

●true 일 때는 CGLib을 사용한 클래스
기반의 프록시를 만들고 false또는 지정하지 않을  때는 JDK의 프록시를 사용합니다.

order

No

 

트랜잭션
어드바이스가 적용될 순서를 지정합니다.

@Transactional(readOnly = true)
public class DefaultFooService implements FooService {

    public Foo getFoo(String fooName) {
        // do something
    }

    // these settings have precedence for this method
    @Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW)
    public void updateFoo(Foo foo) {
        // do something
    }
}

이렇게 클래스에도 선언하고 메소드에도 선언했을 때에는 메소드에 선언한 설정의 우선순위가 더 높습니다. 따라서 위의 경우 getFoo()는 readOnly 로 처리 하고 updateFoo는 매번 새로운 트랜잭션을 생성해서 처리하며 readOnly 로 처리 되지 않습니다.