Whiteship's Note


트랜잭션 기초

Hibernate/Chapter 10 : 2008.03.27 07:49


  • Atomic: 원자성
  • Consistency: 비지니스 룰을 깨트리면 안 된다.
  • Isolation: 동시에 같은 데이터에 대한 여러 작업이 독립적으로 수행되어야 한다.
  • Durability: 트랜잭션의 결과는 영속적으로 유지되어야 한다.
신고
top


Chapter 10: Transactions

DB/SQL : 2008.01.06 20:46


참조 : The Programmer's Guide to SQL

트랜잭션의 특징 ACID
    - Atomic
    - Consistency
    - Isolation
    - Durable

오라클은 기본으로 Auto Transaction 상태.
    - 첫 번째 SQL문을 실행할 때, 트랜잭션이 자동으로 시작 됨.
    - 따라서 START TRANSACTION(SQL-99 표준) 을 사용하지 않아도 됨.
    - 그러나 10g에서는 기본으로 오토커밋 상태임.

사용자 삽입 이미지

오토커밋
    - 이 상태에서는 모든 SQL문을 개별 트랜잭션으로 처리함.
    - SET AUTOCOMMIT ON/OFF 오라클에서 오토커밋 상태로 전환 하는 방법.

롤백하기
    - ROLLBACK [세이브포인트 이름]
    - SAVEPOINT 이름 생략하면, 트랜잭션 시작 이전 상태로 돌아감.

세이브포인트 만들기
    - SAVEPOINT [이름];

커밋하기
    - COMMIT

트랜잭션 예제

BEGIN

   INSERT INTO Student (StudentID, Name) VALUES (101, 'Dave');
   INSERT INTO Student (StudentID, Name) VALUES (102, 'Claire');

   SAVEPOINT BeforeAddingAnne;
   INSERT INTO Student (StudentID, Name) VALUES (103, 'Anne');
   ROLLBACK TO BeforeAddingAnne;

   COMMIT;

EXCEPTION
   WHEN OTHERS
      THEN ROLLBACK;
END;
/

오라클의 Isolation level
    - 기본은 Read Commited
    - Read Uncommited와 Repeatable Read는 지원하지 않음.
    - Isolaction Level 변경하는 방법
    SET TRANSACTION
    { { READ ONLY | READ WRITE }
      | ISOLATION LEVEL
        { READ COMMITTED
        | SERIALIZABLE } };

동기화 테스트 하려면, 오토커밋 상태가 아닌 상태에서 두 개의 창을 띄워 놓고 하면 됨.(READ COMMITED 상태)
    - 한 쪽 창에서 한 개의 레코드를 추가한다.
    - 추가 됐는지 SELECT 문으로 확인한다.
    - 다른 쪽 창에서 SELECT 해본다.
    - 다른 쪽 창에는 첫 번째 창에서 추가한 레코드가 보이지 않는다.
    - 첫 번째 창의 SQL이 아직 커밋되지 않았기 때문이다.
    - 첫 번째 창에서 COMMIT 을 실행한다.
    - 두 번째 창에서 SELECT로 확인한다. 이번에는 보인다.

신고
top

DB/SQL : 2008.01.06 20:46 Trackback. : Comment.

Transaction 관련 API

Spring/Chapter 9 : 2007.04.16 12:10


J2EE without EJB p242 의 그림입니다.
사용자 삽입 이미지

TransactionDefinition, TransactionStatus, PlatformTransactionManager
사용자 삽입 이미지

PlatformTransactionManager 인터페이스를 구현한 클래스들
AbstractPlatformTransactionManager, CciLocalTransactionManager, DataSourceTransactionManager, HibernateTransactionManager, HibernateTransactionManager, JdoTransactionManager, JmsTransactionManager, JmsTransactionManager102, JpaTransactionManager, JtaTransactionManager, OC4JJtaTransactionManager, TopLinkTransactionManager, WebLogicJtaTransactionManager

TransactionDefinition 인터페이스르 구현한 클래스들
DefaultTransactionAttribute, DefaultTransactionDefinition, DelegatingTransactionAttribute, RuleBasedTransactionAttribute, TransactionTemplate

TransactionException 은 모두 RuntimeException으로 un-checked Exception입니다.
사용자 삽입 이미지



신고
top


9.7. Choosing between programmatic and declarative transaction management

Spring/Chapter 9 : 2007.04.16 11:26


programmatic transaction management

트랜잭션 처리를 할 부분이 매우 일부라면 트랜잭션 프록시 같은 것을 사용하지 않고 그냥 TransactionTemplate 을 사용하여 처리하는 것을 권장합니다.

트랜잭션 이름을 명시적으로 사용할 수 있다는 것도 이런 방법의 장점 중 하나입니다.[각주:1]

declarative transaction management

트랜잭션 처리 할 부분이 많다면 비즈니스 로직에서 분리 해내고 쉽게 설정할 수 있는 요 방법을 사용하는 것이 좋습니다.
  1. 선언적인 방법에서는 트랜잭션 이름을 (아직까진) 명시적으로 줄 수 없었습니다. [본문으로]
신고
top


9.6. Programmatic transaction management

Spring/Chapter 9 : 2007.04.16 11:14


선언적인 방법이 아니고 프로그래밍을 통해 트랜잭션 관리를 할 때 두 가지 경우가 있습니다.
1. TransactionTemplate 사용 할 경우
2. PlatformTransactionManager 를 구현한 클래스를 직접 사용 할 경우

9.6.1. Using the TransactionTemplate

private final TransactionTemplate transactionTemplate;

이렇게 멤버로 지정해 놓고 사용하면 됩니다. 먼저 트랜잭션의 속성을 설정하는 방법은 다음과 같습니다.

    public SimpleService(PlatformTransactionManager transactionManager) {
        Assert.notNull(transactionManager, "The 'transactionManager' argument must not be null.");
        this.transactionTemplate = new TransactionTemplate(transactionManager);

        // the transaction settings can be set here explicitly if so desired         this.transactionTemplate.setIsolationLevel(TransactionDefinition.ISOLATION_READ_UNCOMMITTED);
        this.transactionTemplate.setTimeout(30); // 30 seconds
        // and so forth...
    }

아니면 XML에서 설정하고 세터나 생성자 인젝션을 사용하면 되겠습니다.

<bean id="sharedTransactionTemplate"
      class="org.springframework.transaction.support.TransactionTemplate>
    <property name="isolationLevelName" value="ISOLATION_READ_UNCOMMITTED"/>
    <property name="timeout" value="30"/>
</bean>

트랜잭션 탬플릿을 사용해서 어떤 작업을 할 때는 다음과 같이 TransactionCallback 을 사용합니다. 탬플릿과 콜백에 대한 이해는 이 글을 참조하시길 초 강추 합니다.

1. 리턴 값이 있는 경우
public Object someServiceMethod() {
        return transactionTemplate.execute(new TransactionCallback() {

            // the code in this method executes in a transactional context
            public Object doInTransaction(TransactionStatus status) {
                updateOperation1();
                return resultOfUpdateOperation2();
            }
        });
    }

2. 리턴 값이 없는 경우
public void someServiceMethod2() {
    transactionTemplate.execute(new TransactionCallbackWithoutResult() {
   
        protected void doInTransactionWithoutResult(TransactionStatus status) {
            updateOperation1();
            updateOperation2();
        }
    });
}

9.6.2. Using the PlatformTransactionManager

DefaultTransactionDefinition def = new DefaultTransactionDefinition();
// explicitly setting the transaction name is something that can only be done programmatically
def.setTransactionName("SomeTxName");
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);

TransactionStatus status = txManager.getTransaction(def);
try {
    // execute your business logic here
}
catch (MyException ex) {
    txManager.rollback(status);
    throw ex;
}
txManager.commit(status);

TransactionDefinition, TransacionStatus, TransactionManager 객체를 직접 사용하여 트랜잭션 속성을 설정하고 롤백 또는 커밋을 하는 코드를 직접 작성하는 방법입니다. 이 세개의 객체들에 대한 관계는 without EJB의 트랜잭션 부분 242페이지에 잘 나와있습니다.

신고
top


9.5.7. Advising transactional operations

Spring/Chapter 9 : 2007.04.16 08:45


트랜잭션 어드바이스과 일반 어드바이스를 모두 적용하고 싶을 때 Order 인터페이스를 사용하여 순서를 지정할 수 있습니다.

   <bean id="profiler" class="x.y.SimpleProfiler">
        <!-- execute before the transactional advice (hence the lower order number) -->
        <property name="order" value="1"/>
    </bean>
   
    <tx:annotation-driven transaction-manager="txManager"/>

    <aop:config>
        <!-- this advice will execute around the transactional advice -->
        <aop:aspect id="profilingAspect" ref="profiler">
            <aop:pointcut id="serviceMethodWithReturnValue"
                          expression="execution(!void x.y..*Service.*(..))"/>
            <aop:around method="profile" pointcut-ref="serviceMethodWithReturnValue"/>
        </aop:aspect>
    </aop:config>

트랜잭션 처리를 어노테이션을 사용했기 때문에 XML 설정만 보고서는 순서를 예측할 수가 없습니다. 전부 XML로 설정한 예제를 보겠습니다.

    <!-- the profiling advice -->
    <bean id="profiler" class="x.y.SimpleProfiler">
        <!-- execute before the transactional advice (hence the lower order number) -->
        <property name="order" value="1"/>
    </bean>

    <aop:config>
       
        <aop:pointcut id="entryPointMethod" expression="execution(* x.y..*Service.*(..))"/>

        <!-- will execute after the profiling advice (c.f. the order attribute) -->
        <aop:advisor
                advice-ref="txAdvice"
                pointcut-ref="entryPointMethod"
                order="2"/> <!-- order value is higher than the profiling aspect -->

        <aop:aspect id="profilingAspect" ref="profiler">
            <aop:pointcut id="serviceMethodWithReturnValue"
                          expression="execution(!void x.y..*Service.*(..))"/>
            <aop:around method="profile" pointcut-ref="serviceMethodWithReturnValue"/>
        </aop:aspect>

    </aop:config>

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

이번에는 트랜잭션 어드바이저의 order가 2 라는 것이 눈에 들어옵니다. 프로파일링 어스펙트의 order가 1이기 때문에 프로파일링 어드바이스가 먼저 적용이 될 것입니다.

의문이 드는건 왜 하나는 어드바이저 단위에 order를 설정하고 다른 하나는 어스펙트 단위에 order를 설정하였느냐 인데 트랜잭션 어드바이저 말고 커스텀 어드바이스들을 기본적으로 먼저 실행하겠다는 의도가 아닐까 생각해 봅니다.
신고
top


@Transactional 속성들

Spring/Chapter 9 : 2007.04.15 08:43


사용자 삽입 이미지
아직 name 속성은 없습니다. name 속성을 사용해서 로깅이나 트랜잭션 모니터링을 할 때 트랜잭션 이름을 원하는 이름으로 출력할 수 있을 겁니다. 하지만 지금은 "패키지 경로가 붙은 클래스 이름.해당 메소드"가 기본 이름이 됩니다.

Property

Type

Description

propagation

enum: Propagation

optional propagation setting

isolation

enum: Isolation

optional isolation level

readOnly

boolean

read/write vs. read-only transaction

timeout

int (초 단위)

the transaction timeout

rollbackFor

Throwable 타입의 Class 객체의 배열

발생했을 때 반드시 롤백 해야 하는 예외 클래스들

rollbackForClassname

Throwable 타입의 Class 이름의 배열

발생했을 때 반드시 롤백 해야 하는 예외 클래스들의 이름

noRollbackFor

Throwable 타입의 Class 객체의 배열

발생했을 때 롤백 하지 않아도 되는 예외 클래스들.

noRollbackForClassname

Throwable 타입의 Class 이름의 배열

발생했을 때 롤백 하지 않아도 되는 예외 클래스들의 이름


신고
top


9.5.6. Using @Transactional

Spring/Chapter 9 : 2007.04.14 22:58


이전에 봤던 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는 등록되어 있어야겠죠.[각주:1]

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

이유는? - 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 로 처리 되지 않습니다.
  1. <a href="http://whiteship.tistory.com/698" target="_blank">이전</a>에 살펴봤지만 transactionManager라는 이름으로 등록되어 있다면 굳이 명시적으로 tracsaction-manger 라는 속성을 사용하지 않도 알아서 찾게 됩니다. [본문으로]
신고
top


Isolation levels

Spring/Chapter 9 : 2007.04.13 12:11


여러 트랜잭션들이 동시 다발적으로 데이타에 접근하여 작업을 할 때 다음의 문제들이 발생할 수 있습니다.

Dirty read: 어떤 트랜잭션 T1이 다른 트랜잭션 T2가 아직 커밋하지 않은 데이타를 읽었는데 T2가 롤백 되는 경우. T1이 읽은 데이타는 dirty.

Nonrepeatable read: 어떤 트랜잭션 T1이 계속 해서 같은 쿼리를 날리는데 그 사이에 다른 트랜잭션 T2가 데이타를 수정하면 T1은 의아해 합니다. 대체 왜 값이 바뀐거지?

Phantom read: 어떤 트랜잭션 T1이 계속 또 쿼리를 날리는데 그 사이 다른 트랜잭션 T2가 새로운 데이타를 추가합니다. T1은 갑자기 나타난 데이타를 보고 귀신을 본 것 처럼 깜짝 놀랍니다.

Lock이라는 것을 레코드 단위로 걸어버리면 저런 문제들이 전혀 발생하지 않겠지만 성능 문제가 심각하게 되겠죠. 따라서 다음과 같은 Isolation level 이 존재합니다.

Isolation level

What it means

ISOLATION_DEFAULT

DB가 사용하는 isolation level을 따릅니다.

ISOLATION_READ_UNCOMMITTED

아직 커밋되지 않은 트랜잭션에 의해 변경된 데이터를 읽을 수 있습니다.

따라서 위에서 지적한 세 개의 문제가 모두 발생할 수 있습니다.

ISOLATION_READ_COMMITTED

●커밋 된 데이터만 읽을 수 있습니다.

Dirty read는 방지할 수 있지만 나머진 발생할 수 있습니다.

ISOLATION_REPEATABLE_READ

●현재 트랜잭션에 의해 데이터를 수정하지 않았다면 항상 같은 데이터를 읽게 합니다.

Dirty readNonrepeatable read는 방지할 수 있지만 Phantom read는 방지할 수 없습니다.

ISOLATION_SERIALIZABLE

●모든 문제를 다 방지할 수 있지만 성능이 가장 좋지 않습니다..




신고
top


Propagation behavior

Spring/Chapter 9 : 2007.04.13 11:48


Spring In Action을 보니 다음과 같이 적혀 있습니다.

Propagation behavior defines the boundaries of the transaction with respect to
the client and to the method being called.

클라이언트(?)와 메소드가 실행되는 트랜잭션 경계를 정의하는 속성인 듯 합니다. 7 가지 전달 방식이 있습니다.

Propagation Behavior

What it means

PROPAGATION_MANDATORY

반드시 트랜잭션 안에서 실행되어야 합니다.

현재 진행중인 트랜잭션이 없다면 예외가 발생합니다.

PROPAGATION_NESTED

현재 진행중인 트랜잭션이 존재 한다면 그 트랜잭션 내부의 트랜잭션을 생성하여 그 안에서 실행합니다.

내부 트랜잭션은 자기를 감싸고 있는 외부 트랜잭션에 독립적입니다(외부 트랜잭션이 커밋 or 롤백 되든 말든 난 나대로 커밋 or 롤백 하겠다.)

만약에 외부 트랜잭션이 없다면 PROPAGATION_REQUIRED로 지정한 것과 동일하게 수행 됩니다.

이 기능을 지원하지 않는 벤더도 있기 때문에 문서를 참조 하시기 바랍니다

PROPAGATION_NEVER

반드시 트랜잭션 처리 없이 실행되어야 합니다.

●현재 진행중인 트랜잭션이 있다면 예외가 발생합니다.

PROPAGATION_NOT_SUPPORTED

반드시 트랜잭션 처리 없이 실행되어야 합니다.

●현재 진행중인 트랜잭션이 있다면 해당 메소드 실행이 끝날 때까지 트랜잭션을 일시 정지합니다.

PROPAGATION_REQUIRED

반드시 트랜잭션 안에서 실행되어야 합니다.

●현재 진행중인 트랜잭션이 있다면 그것을 사용하고 없다면 새로운 트랜잭션을 시작합니다.

PROPAGATION_REQUIRES_NEW

반드시 자신만을 위한 트랜잭션 만들고 그 안에서 실행되어야 합니다.

●현재 진행중인 트랜잭션이 있다면 해당 메소드 실행이 끝날 때까지 트랜잭션을 일시 정지 합니다.

PROPAGATION_SUPPORTS

●반드시 트랜잭션 안에서 처리해야 할 필요는 없습니다.

●진행중인 트랜잭션이 있다면 트랜잭션 안에서 처리하고 없으면 트랜잭션 없이 처리.



참조 : Spring 워크북, Spring In Action
신고

'Spring > Chapter 9' 카테고리의 다른 글

9.6. Programmatic transaction management  (1) 2007.04.16
9.5.7. Advising transactional operations  (0) 2007.04.16
@Transactional 속성들  (0) 2007.04.15
9.5.6. Using @Transactional  (0) 2007.04.14
Isolation levels  (0) 2007.04.13
Propagation behavior  (0) 2007.04.13
9.5.5. <tx:advice/> settings  (0) 2007.04.12
9.5.4. Configuring different transactional semantics for different beans  (0) 2007.04.12
9.5.3. Rolling back  (0) 2007.04.12
Spring 트랜잭션의 기반은 Spring AOP  (0) 2007.04.12
9.5.2. A first example  (1) 2007.04.12
top


9.5.5. <tx:advice/> settings

Spring/Chapter 9 : 2007.04.12 15:57


AttributeRequired?DefaultDescription
nameYes 

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.

propagationNoREQUIREDThe transaction propagation behavior
isolationNoDEFAULTThe transaction isolation level
timeoutNo-1The transaction timeout value (in seconds)
read-onlyNofalseIs this transaction read-only?
rollback-forNo 

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

no-rollback-forNo 

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이 없다는 뜻일까요?

찾아봐야겠습니다.
신고
top


9.5.4. Configuring different transactional semantics for different beans

Spring/Chapter 9 : 2007.04.12 15:38


여러 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>

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

신고
top


9.5.3. Rolling back

Spring/Chapter 9 : 2007.04.12 15:21


특정 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 코드가 침략하게 됩니다. 따라서 선언적인 방법을 사용하는 것을 권장합니다.
신고
top


Spring 트랜잭션의 기반은 Spring AOP

Spring/Chapter 9 : 2007.04.12 15:05


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

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 를 비교하다니;;; 흠..

신고
top


9.5.2. A first example

Spring/Chapter 9 : 2007.04.12 14:40


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 속성을 사용하여 명시하지 않더라도 알아서 찾을 수 있습니다.[각주:1] 트랜잭션 관리 대상이 될 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.*.*(..))
  1. 이것도 일종의 CoC라고 할 수 있겠습니다. [본문으로]
신고
top


9.5.1. Understanding the Spring Framework's declarative transaction implementation

Spring/Chapter 9 : 2007.04.12 11:47


트랜잭션 관리 대상이 되는 클래스에 @Transactional 어노테이션을 붙이고 설정 파일에는 <tx:annotation-driven/>요렇게 추가하면 됩니다.

사용자 삽입 이미지
그렇게 하면 내부에서는 AOP를 사용하여 타겟에 대한 호출은 (1)AOP 프록시를 호출하게 되고 그 다음 (2)트랜잭션을 만들고 (3)트랜잭션 내에서 원하는 작업을 하고 (4)실제 작업을 한 뒤에 다시 (3)또 해당 작업이 끝난 뒤 원하는 작업을 하고 (2)해당 트랜잭션을 커밋 하거나 롤백하고 (5)최종 결과를 호출한 녀석에게 돌려 줍니다.
신고
top


9.5. Declarative transaction management

Spring/Chapter 9 : 2007.04.11 17:31


Spring도 EJB의 CMT 처럼 선언적인 트랜잭션을 제공하지만 몇 가지 차이가 있습니다.
  • Spring은 EJB의 CMT 처럼 JTA에 종속되어 있지 않습니다. 설정 내용을 살짝 바꾸기만 하면 JDBC, Hibernate, JDO 등을 자유롭게 사용할 수 있습니다.
  • EJB(bean) 만 트랜잭션을 처리할 수 있었는데 반해 Spring은 일반 클래스에도 적용할 수 있습니다.
  • 선언적으로 롤백 룰을 설정할 수 있습니다.
  • AOP를 사용하여 트랜잭션 처리를 할 때 사용자가 원하는 부가적인 기능을 실행할 수 있습니다. EJB에서는 할 수 없습니다.
  • The Spring Framework does not support propagation of transaction contexts across remote calls, as do high-end application servers
롤백 룰을 사용하여 특정 예외가 발생했을 때에만 롤백이 되도록 선언적으로 지정할 수 있습니다.

EJB의 경우 기본 설정이 RemoteException를 제외한 checked 예외(application exception)가 발생하면 롤백하지 않고 Runtime exception(system exception)이 발생하면 자동으로 롤백하도록 되어 있습니다.

이런 기본 설정이 유용하기 때문에 Spring도 EJB의 기본 설정을 따라서 unchecked exception 가 발생할 때에만 자동으로 롤백하도록 기본 설정되어 있습니다.

9.5.1. Understanding the Spring Framework's declarative transaction implementation

Spring의 선언적인 트랜잭션 관리라는 신비를 파해칩니다.

9.5.2. A first example

예제 ㄱㄱ..

9.5.3. Rolling back

간단한 설정을 통해서 롤백을 제어 하는 방법을 설명합니다.

9.5.4. Configuring different transactional semantics for different beans

여러 bean들에 각각 다른 트랜잭션을 적용하는 방법을 설명합니다.

9.5.5. <tx:advice/> settings

<tx:advice/> 태그를 사용하여 트랜잭션 속성을 설정합니다.

9.5.6. Using @Transactional

@Transactional 어노테이션을 사용하여 XML 설정 대신 트랜잭션 대상이 될 bean을 지정할 수 있습니다.

9.5.7. Advising transactional operations

트랜잭션 처리를 해야하는 advice를 엮는 방법을 설명합니다.

9.5.8. Using @Transactional with AspectJ

Spring Container에서 관리하는 bean 말고도 AspectJ를 사용하여 @Trancsational 어노테이션을 적용할 수 있습니다.

신고
top


9.4. Resource synchronization with transactions

Spring/Chapter 9 : 2007.04.11 14:47


이번에 볼 것은 이전 글에서 살펴보았던 (1)각 종 TransactionManager를 사용하여 어떻게 Hibernate나 JDBC에 있는 트랙잭션 관련 API를 사용하느냐 (2)해당 자원[각주:1]을 잘 가져왔고 creation/reuse/cleanup/trigger/transaction synchronization이 필요할 때 잘 동작하는지 확인 하는 것 입니다.

9.4.1. High-level approach

추천하는 방법으로 추상화 단계가 높은 Template 클래스를 사용하여  creation/reuse/cleanup/trigger/transaction synchronization 이런 일들을 할 수 있습니다.

예외를 전부 매핑해줍니다.

내부적으로 해당 자원의 API를 사용하는 것이지 Spring 의 API가 대체하는 것은 아닙니다.
'수' 작업으로 만든 HibernateTemplate

ex) HibernateTemplate, JdbcTemplate, JdoTemplate

9.4.2. Low-level approach

추상화 단계가 낮은 Utils 클래드를 사용해서 원하는 작업을 할 수도 있습니다.

Connection conn = DataSourceUtils.getConnection(dataSource);
이런식으로 사용하며 역시 예외를 전부 맵핑해서 좀더 유용한  unchecked 예외로 뿌려 줍니다.

ex) DataSourceUtils, SessionFactoryUtils, PersistenceManagerFactoryUtils

9.4.3. TransactionAwareDataSourceProxy

가장 낮은 단계의 클래스로 타겟 DataSource의 프록시입니다. Spring이 관리하는 트랙잭션이라는 정보를 추가하기 위해 타겟 DataSource를 감쌉니다. DataSource 인터페이 타입을 요구하는 기존 코드에서 작업해야 한다면 이 걸 사용할 수 있겠습니다.

그런 경우가 아니라면 추상화 단계가 높은 것을 사용하길 권장합니다.




  1. Hibernate나 JDBC, JTA등의 실제 트랜잭션을 처리하는 녀석들을 Resource라고 표현하고 있습니다. [본문으로]
신고
top


9.3. Key abstractions

Spring/Chapter 9 : 2007.04.11 12:17


Spring의 트랜잭션 추상화 계층에서 트랜잭션 전략(transaction strategy)이 중요한 개념 중 하나입니다.

트랜잭션 전략을 위해서 PlatformTransactionManager 인터페이스를 사용합니다.
public interface PlatformTransactionManager {

    TransactionStatus getTransaction(TransactionDefinition definition)
        throws TransactionException;

    void commit(TransactionStatus status) throws TransactionException;

    void rollback(TransactionStatus status) throws TransactionException;
}

1. 인터페이스 라는 것.
= 필요할 때 mock이나 stub을 만들어 사용할 수 있다. => 테스트 용이함.
= 인터페이스를 활용하여 구현 가능. => OOP 원칙 따름.

2. 위 인터페이스에 있는 모든 메소드에서 unchecked 예외를 발생시킨다는 것.
= 불 필요한 try-catch 문 사용 안 해도 됨.
= 물론 잡을 수 도 있지만 치명적이기 때문에 마땅히 할 수 있는 일도 없다. => 그냥 안 잡는게 타당함.

PlatformTransactionManager 인터페이스를 구현한 클래스들 입니다.[각주:1]
AbstractPlatformTransactionManager, CciLocalTransactionManager, DataSourceTransactionManager, HibernateTransactionManager, HibernateTransactionManager, JdoTransactionManager, JmsTransactionManager, JmsTransactionManager102, JpaTransactionManager, JtaTransactionManager, OC4JJtaTransactionManager, TopLinkTransactionManager, WebLogicJtaTransactionManager
첫번째에 있는 메소드를 좀 더 자세히 살펴보겠습니다.

인자로 TransactionDefinition 인터페이스를 넘겨 주고 TransactionStatus 인터페이스 타입의 객체를 받아 올 수 있습니다.

TransactionDefinition 인터페이스
에서 다음의 트랜잭션 속성을 설정할 수 있습니다.

Isolation: 다른 트랜잭션의 작업으로 부터 해당 트랜잭션이 얼마나 고립되어 있는지 정도.
ex) 다른 트랙잭션에 의해 쓰여졌지만 커밋은 되지 않은 것을 볼 수 있는가?

Propagation: 기존에 존재하는 트랜잭션 문맥이 있는 상태에서 어떻게 수행할지 선택할 수 있는 옵션.
ex1) 그냥 기존에 있는 트랜잭션 내에서 처리 한다.
ex2) 기존의 트랜잭션을 종료하고 새로운 트랜잭션에서 처리한다.

Timeout: 정해 준 시간이 지날 경우 타임 아웃 되며 자동으로 롤백 됩니다.

Read-only status: 이 상태로 설정해 주면 어떤 데이타도 수정할 수 없습니다. 최적화를 위해 유용하게 사용할 수 있습니다. (such as when using Hibernate).

TransactionStatus 인터페이스는 이름 그대로 트랜잭션의 상태에 관한 정보를 가져올 수 있고 예외를 발생하는 방법이 아닌 프로그래밍 적으로 롤백을 설정할 수 있습니다.


  1. HibernateTransactionManager가 두 개 인데요. 이 중에 하나는 Hibernate 3쩜대 용입니다. [본문으로]
신고
top


Transaction management

Spring/Chapter 9 : 2007.04.11 01:00


9.1. Introduction

트랜잭션 관리를 위한 추상화를 통해 다음의 장점들을 제공합니다.
  • JTA, JDBC, Hibernate, JPA, and JDO와 같은 다른 트랜잭션 관리 API 간에도 일관된 프로그래밍을 할 수 있습니다.
  • 선언적인 트랜잭션 관리를 할 수 있습니다.
  • JTA 같은 복잡한 방법이 아닌 단순한 API를 제공합니다.
  • Spring의 다양한 데이타 접근 추상화(data access abstractions)와 통합하기 좋습니다.
9.2. Motivations

EJB CMT 또는 Hibernate 같은 독자적인 API를 사용한 트랜잭션 관리 대신 Spring 프레임워크의 트랜잭션 추상화를 사용하기 원하는 이유에 대해 나옵니다.

9.3. Key abstractions

Spring 프레임워크의 트랜잭션 지원을 위한 핵심 클래스들을 소개하고 어떻게 설정하고 다양한 자원으로 부터 DataSource 객체를 얻을 수 있는지 설명합니다.

9.4. Resource synchronization with transactions

어떻게 어플리케이션 코드에서 직접적으로 또는 간접적으로 퍼시스턴트의 API를 사용할 수 있는지 설명합니다.

9.5. Declarative transaction management

Spring AOP를 사용하여 기존 코드에 가장 적은 영향을 주며 선언적으로 트랜잭션 관리를 할 수 있도록 하는 방법을 설명합니다.

9.6. Programmatic transaction management

프로그래밍을 통한 트랜잭션 관리 방법에는 TransactionTemplate 과 PlatformTransactionManager 사용하는 두 가지가 있는데 이 중에 첫번째 방법을 권장합니다.

9.7. Choosing between programmatic and declarative transaction management

선언적인방법과 프로그래밍을 통한 방법의 장단점을 살펴 봅니다.

9.8. Application server-specific integration

Spring 프레임워크의 트랜잭션 추상화는 일반적으로 서버를 인지 하지 못합니다. 부가적으로 특정 웹서버를 위한 클래스를 제공합니다.

9.9. Solutions to common problems

특정 DataSource를 위한 잘못된 트랜잭션 메니저 사용에 관한 내용이 있습니다.

9.10. Further Resources

This book, Java Transaction Design Strategies from InfoQ

신고
top







티스토리 툴바