9.5.5. settings

Attribute Required? Default Description
name Yes  

The method name(s) with which the transaction attributes
are to be associated. The wildcard (*) character can be used to
associate the same transaction attribute settings with a number
of methods; for example, 'get*',
'handle*', 'on*Event', etc.

propagation No REQUIRED The transaction propagation behavior
isolation No DEFAULT The transaction isolation level
timeout No -1 The transaction timeout value (in seconds)
read-only No false Is this transaction read-only?
rollback-for No  

The Exception(s) that will trigger
rollback; comma-delimited. For example,
'com.foo.MyBusinessException,ServletException'

no-rollback-for No  

The Exception(s) that will
not trigger rollback; comma-delimited.
For example,
'com.foo.MyBusinessException,ServletException'

트랜잭션 어드바이(<tx:advice/>)에 설정할 수 있는 트랜잭션 설정입니다. name 속성만 필수도 나머지 속성들은 설정해 주지 않으면 디폴트 값을 가지게 됩니다.

propagation과 isolation 에는 어떤 값을 줄 수 있고 주는 값들에 따라 어떻게 변한다는 설명이 없네요. 궁금한데;;

timeout 의 기본값이 -1 이라는 무슨 뜻일까요? 0 도 아니고.. -1 은…뭐지.. 아~ timeout이 없다는 뜻일까요?

찾아봐야겠습니다.

9.5.4. Configuring different transactional semantics for different beans

여러 bean들 각각에 다른 advice 적용하는 방법입니다.

포인트컷으로 적용 대상을 골라 낼 수 있겠습니다.

    <aop:config>
        <aop:pointcut id=”serviceOperation”
                    expression=”execution(* x.y.service..*Service.*(..))“/>
        <aop:advisor pointcut-ref=”serviceOperation” advice-ref=”txAdvice”/>
    </aop:config>

    <!– these two beans will be transactional… –>
    <bean id=”fooService” class=”x.y.service.DefaultFooService”/>
    <bean id=”barService” class=”x.y.service.extras.SimpleBarService”/>

    <!– … and these two beans won’t –>
    <bean id=”anotherService” class=”org.xyz.SomeService”/> <!– (not in the right package) –>
    <bean id=”barManager” class=”x.y.service.SimpleBarManager”/> <!– (doesn’t end in ‘Service’) –>

    <tx:advice id=”txAdvice”>
        <tx:attributes>
            <tx:method name=”get*” read-only=”true”/>
            <tx:method name=”*”/>
        </tx:attributes>
    </tx:advice>

포인트컷으로 x.y.service 패키지의 Service가 들어가는 클래스로 범위를 좁혀서 트랜잭션을 적용하고 있습니다.

여러 개의 트랜잭션 설정이 필요하다면 다음과 같이 어드바이저를 여러개 만들면 됩니다.

    <aop:config>
        <aop:pointcut id=”defaultServiceOperation
                    expression=”execution(* x.y.service.*Service.*(..))“/>
        <aop:pointcut id=”noTxServiceOperation”
                    expression=”execution(* x.y.service.ddl.DefaultDdlManager.*(..))”/>
        <aop:advisor pointcut-ref=”defaultServiceOperation” advice-ref=”defaultTxAdvice“/>
        <aop:advisor pointcut-ref=”noTxServiceOperation” advice-ref=”noTxAdvice”/>
    </aop:config>

    <!– this bean will be transactional (see the ‘defaultServiceOperation’ pointcut) –>
    <bean id=”fooService” class=”x.y.service.DefaultFooService”/>

    <!– this bean will also be transactional, but with totally different transactional settings –>
    <bean id=”anotherFooService” class=”x.y.service.ddl.DefaultDdlManager”/>

    <tx:advice id=”defaultTxAdvice“>
        <tx:attributes>
            <tx:method name=”get*” read-only=”true”/>
            <tx:method name=”*”/>
        </tx:attributes>
    </tx:advice>
   
    <tx:advice id=”noTxAdvice”>
        <tx:attributes>
            <tx:method name=”*” propagation=”NEVER”/>
        </tx:attributes>
    </tx:advice>

각각의 트랜잭션 어드바이스가 적용될 포인트컷을 만들고 그 것들을 가지고 어드바이저로 조합해 두면 됩니다. 간단하네요.

9.5.3. Rolling back

특정 Exception이 발생 했을 때 롤백하도록 설정하는 방법도 역시 선언적인 방법과 프로그래밍을 통한 방법이 있습니다.

선언적인 방법은 다음과 같이 rollback-for 속성을 사용하여 설정할 수 있습니다.

<tx:advice id=”txAdvice” transaction-manager=”txManager”>
  <tx:attributes>
     <tx:method name=”get*” read-only=”false” rollback-for=”NoProductInStockException”/>
     <tx:method name=”*”/>
  </tx:attributes>
</tx:advice>

프로그래밍을 통한 방법은 다음과 같이 할 수 있습니다.

public void resolvePosition() {
    try {
        // some business logic…
    } catch (NoProductInStockException ex) {
        // trigger rollback programmatically
        TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
    }
}

하지만 Spring 프레임워크 코드에 종속성이 생기게 되며, Spring 코드가 침략하게 됩니다. 따라서 선언적인 방법을 사용하는 것을 권장합니다.

Spring 트랜잭션의 기반은 Spring AOP

라는 건 이미 레퍼런스에도 명시되어 있습니다. 그렇기 때문에 아래와 같이 사용법에 있어서 공통점이 존재하는 것 같습니다.

Spring에서 AOP를 사용법을 구분하는 여러 구분자가 있을 수 있겠지만 간단한 declarative 하느냐 programmatically 하느냐로 나눌 수도 있겠습니다.

Spring에서 트랜잭션 관리도 마찬가지로 선언적인 방법과 프로그래밍을 통한 방법으로 나뉩니다.

Spring AOP 사용 방법 중 declarative 한 방법은 다시 어노테이션을 사용하는 방법(@AspectJ)과
XML 설정(Schema-based Spring AOP)을 사용하는 방법으로 나눌 수 있습니다.

Spring 트랜잭션 역시 어노테이션을 사용하는 방법(@Transactional)과 XML 설정(Schema-based Spring AOP를 사용한 예제)을 사용하는 방법으로 나눌 수 있습니다.

그런데 막상 적어 놓고 보니까 이런 비교는 좀 무의미 한 것 같네요. 이렇게 사용 방법이 똑같이 생긴게 어쩌면 당연한거 겠죠?

A U B = A 인데 A 와 B 를 비교하다니;;; 흠..

9.5.2. A first example

Spring Refrence에 있는 설정 파일을 보도록 하겠습니다.

<?xml version=”1.0″ encoding=”UTF-8″?>
<beans xmlns=”http://www.springframework.org/schema/beans”
    xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”
    xmlns:aop=”http://www.springframework.org/schema/aop”
    xmlns:tx=”http://www.springframework.org/schema/tx
    xsi:schemaLocation=”
       http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
       http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd
       http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd”>

//bean 설정이 들어갈 곳

</beans>

XML에서 사용 할 트랜잭션 관련 XML스키마를 추가 합니다. 그리고 bean 설정이 들어갈 곳에 트랜잭션 어드바이스를 추가합니다.

<tx:advice id=”txAdvice” transaction-manager=”txManager”>
        <tx:attributes>
            <tx:method name=”get*” read-only=”true” />
            <tx:method name=”*” />
        </tx:attributes>
</tx:advice>

get으로 시작하는 메소드는 read-only 상태로 읽고 나머지 메소드는 기본 설정 대로 트랜잭션 속성을 지정한 트랜잭션 어드바이스를 만듭니다.

transaction-manager 속성에 넣어준 bean은 다음과 같습니다.

<bean id=”txManager”
        class=”org.springframework.jdbc.datasource.DataSourceTransactionManager“>
        <property name=”dataSource” ref=”dataSource” />
</bean>

실제 트랜잭션을 관리할 bean으로 만약 이 bean의 이름을 transactionManager 라고 설정했다면 트랙잰션 어드바이스에서 굳이 transaction-manager 속성을 사용하여 명시하지 않더라도 알아서 찾을 수 있습니다.[footnote]이것도 일종의 CoC라고 할 수 있겠습니다.[/footnote] 트랜잭션 관리 대상이 될 dataSource를 주입해줘야 하는 군요. 그건 그냥 하면 되겠죠.

다시 돌아가서 트랜잭션 어드바이스를 주입할 포인트 컷과 묶어서 어드바이저를 만들어 줍니다.

<aop:config>
        <aop:pointcut id=”fooServiceOperation”
            expression=”execution(* x.y.service.FooService.*(..))” />
        <aop:advisor advice-ref=”txAdvice”
            pointcut-ref=”fooServiceOperation” />
</aop:config>

이렇게 설정 해 두면 FooService에 있는 모든 메소드에 트랜잭션 어드바이스가 적용될 것입니다. 모든 service 패키지에 있는 모든 클래스의 모든 메소드에 적용하고 싶다면 위의 빨간글씨 부분을 다음과 같이 수정하면 됩니다. x.y.service.*.*(..))