Spring 프레임워크 워크북 정리노트 - Chapter5. Spring 트랜잭션 :: 스프링(spring)/아이바티스(IBatis)/하이버네이트(Hibernate)[SSISO Community]
 
SSISO 카페 SSISO Source SSISO 구직 SSISO 쇼핑몰 SSISO 맛집
추천검색어 : JUnit   Log4j   ajax   spring   struts   struts-config.xml   Synchronized   책정보   Ajax 마스터하기   우측부분

스프링(spring)/아이바티스(IBatis)/하이버네이트(Hibernate)
[1]
등록일:2008-06-11 16:49:06 (0%)
작성자:
제목:Spring 프레임워크 워크북 정리노트 - Chapter5. Spring 트랜잭션

Chapter5. Spring 트랜잭션

1. 문제점 및 해결 방법

4장 게시판 예제에서 BOARD 테이블과 BOARDFILE 테이블에 데이터가 추가되는데, BOARDFILE 테이블에 데이터를 추가하는 중에 에러가 발생하면 BOARD 테이블에 추가되었던 데이터가 롤백되지 않으며 BOARDSEQUENCE, BOARDFILESEQUENCE 테이블의 값 또한 롤백되지 않는다.

Spring JDBC를 기반으로 개발할 경우 개발자들은 Connection 인스턴스에 직접적으로 접근하지 않기 때문에 Connection 인스턴스를 기반으로 트랜잭션을 처리하는 것이 힘들어진다.
Spring 프레임워크는 이와 같은 문제점을 해결하기 위하여 트랜잭션을 처리하기 위한 새로운 API를 제공하고 있다.
Spring 프레임워크는 트랜잭션을 처리하기 위한 방법으로 소스 코드 내에서 프로그램적으로 처리하는 방법과 빈 설정 파일에서 선언적으로 처리하는 두 가지 방법을 지원한다.


2. Spring 트랜잭션 기본

트랜잭션 지원 핵심 API : PlatformTransactionManager, TransactionDefinition, TransactionStatus

    트랜잭션은 Atomicity, Consistency, Isolation, Durability 네 가지 속성을 가진다.

Atomicity (원자성)

트랜잭션 내에 있는 모든 작업이 완료되거나 모든 작업이 완료되지 않아야 한다.
즉, 트랜잭션 내의 작업 중 하나라도 에러가 발생하면 트랜잭션 내의 모든 작업이 롤백(Rollback) 되어야 한다.

Consistency (일관성)

트랜잭션 중에 오류 없이 유효한 데이터만 데이터베이스에 저장되어야 한다.

Isolation (격리성)

트랜잭션 중에 변경된 내용이 트랜잭션이 완료되기 전까지 다른 트랜잭션에 영향을 미쳐서는 안 된다.

Durability (지속성)

트랜잭션이 완료된 경우 시스템 고장이나 네트워크 에러 등으로 데이터가 유실되지 않고 정상적으로 기록되어야 한다.


TransactionDefinition : 트랜잭션 제어 정의
    - 트랜잭션의 네 가지 속성(ACID) 중 개발자들이 제어 가능한 부분(트랜잭션 전달(Propagation), timeout, read-only 상태, 격리셩(Isolation) 레벨의 네 가지 속성)을 추상화

    TransactionDefinition.java

    package org.springframework.transaction;

    public interface TransactionDefinition {

        // 트랜잭션이 실행되어야 하는 범위에 대한 제어와
        // 여러 개의 트랜잭션이 어떻게 상호작용하는지에 대하여 결정하는 것이 가능하다.
        int getPropagationBehavior();

        // 실행하는 트랜잭션의 격리 레벨을 지정하는 것이 가능하다.
        // 즉, 현재 트랜잭션 내에서 변경된 데이터가 다른 트랜잭션에 반영될지에 대한 레벨을 결정하는 것이 가능하다.
        int getIsolationLevel();

        // 실행하는 트랜잭션이 시작해서 종료할 때까지의 시간을 초 단위로 제어하는 것이 가능하다.
        int getTimeout();

        // 실행하는 트랜잭션이 read-only 상태인지 아닌지를 결정하는 것이 가능하다.
        boolean isReadOnly();

    }


격리 레벨(Isolation Level)과 전달 행위(Propagation Behavior)는 트랜잭션이 어떻게 동작해야 되는지를 결정하기 위하여 여러 개의 값으로 나뉘어진다.

트랜잭션 격리 레벨 (Isolation Level)

격리 레벨 (Isolation Level)

상세 설명

TransactionDefinition.
ISOLATION_DEFAULT

개별적인 PlatformTransactionManager를 위한 디폴트 격리 레벨

TransactionDefinition.
ISOLATION_READ_UNCOMMITTED

격리 레벨 중 가장 낮은 격리 레벨이다. 이 격리 레벨은 다른 Commit 되지 않은 트랜잭션에 의해 변경된 데이터를 볼 수 있기 때문에 거의 트랜잭션의 기능을 수행하지 않는다.

TransactionDefinition.
ISOLATION_READ_COMMITTED

대개의 데이터베이스에서의 디폴트로 지원하는 격리 레벨이다. 이 격리 레벨은 다른 트랜잭션에 의해 Commit 되지 않은 데이터는 다른 트랜잭션에서 볼 수 없도록 한다. 그러나 개발자들은 다른 트랜잭션에 의해 입력되거나 수정된 데이터는 조회할 수 있다.

TransactionDefinition.
ISOLATION_REPEATABLE_READ

ISOLATION_READ_COMMITTED 보다는 다소 엄격한 격리 레벨이다. 이 격리 레벨은 다른 트랜잭션이 새로운 데이터를 입력했다면 새롭게 입력된 데이터를 조회할 수 있다는 것을 의미한다.

TransactionDefinition.
ISOLATION_SERIALIZABLE

가장 많은 비용이 들지만 신뢰할 만한 격리 레벨을 제공하는 것이 가능하다. 이 격리 레벨은 하나의 트랜잭션이 완료된 후에 다른 트랜잭션이 실행하는 것처럼 지원한다.


전달 행위 (Propagation Behavior)

전달 행위 (Propagation Behavior)

    상세 설명

TransactionDefinition.
PROPAGATION_REQUIRED

이미 하나의 트랜잭션이 존재한다면 그 트랜잭션을 지원하고, 트랜잭션이 없다면 새로운 트랜잭션을 시작한다.

TransactionDefinition.
PROPAGATION_SUPPORTS

이미 트랜잭션이 존재한다면 그 트랜잭션을 지원하고, 트랜잭션이 없다면 비-트랜잭션 현태로 수행한다.

TransactionDefinition.
PROPAGATION_MANDATORY

이미 트랜잭션이 존재한다면 그 트랜잭션을 지원하고, 활성화된 트랜잭션이 없다면 예외를 던진다.

TransactionDefinition.
PROPAGATION_REQUIRES_NEW

언제나 새로운 트랜잭션을 시작한다. 이미 활성화된 트랜잭션이 있다면 일시 정지한다.

TransactionDefinition.
PROPAGATION_NOT_SUPPORTED

활성화된 트랜잭션을 가진 수행을 지원하지 않는다. 언제나 비-트랜잭션으로 수행하고 존재하는 트랜잭션은 일시 정지한다.

TransactionDefinition.
PROPAGATION_NEVER

활성화된 트랜잭션이 존재하더라도 비-트랜잭션적으로 수행한다. 활성화된 트랜잭션이 존재한다면 예외를 던진다.

TransactionDefinition.
PROPAGATION_NESTED

활성화된 트랜잭션이 존재한다면 내포된 트랜잭션으로 수행된다. 작업 수행은 TransactionDefinition.PROPAGATION_REQUIRED 으로 세팅된 것처럼 수행된다.


▶ TransactionStatus : 트랜잭션의 상태 관리
    - PlatformTransactionManager 에서 트랜잭션을 Commit 할 지 Rollback 할 지를 결정하기 위하여 사용
    TransactionStatus.java

    package org.springframework.transaction;

    public interface TransactionStatus extends SavepointManager {

        boolean isNewTransaction();

        void setRollbackOnly();

        boolean isRollbackOnly();

    }


▶ PlatformTransactionManager : 실질적인 트랜잭션 실행
    - 트랜잭션 내에서 에러 없이 모든 작업을 완료할 경우에는 Commit, 에러가 발생할 경우에는 Rollback 작업을 실행할 수 있도록 지원한다.

    PlatformTransactionManager.java

    package org.springframework.transaction;

    public interface PlatformTransactionManager {

        TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException;

        void commit(TransactionStatus status) throws TransactionException;

        void rollback(TransactionStatus status) throws TransactionException;

    }


3. Spring 트랜잭션 선언적 처리

    applicationContext-jdbc.xml - 선언적 트랜잭션 설정

    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="datasource" ref="dataSource">
    </bean>
    <bean id="txProxyTemplate" abstract="true" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
        <property name="transactionManager">
            <ref bean="transactionManager" />
        </property>
        <property name="preInterceptors">
            <list>
                <ref bean="loggingAdvice" />
                <ref bean="emailNotificationThrowsAdvice" />
            </list>
        </property>
        <property name="transactionAttributes">
            <props>
                <prop key="add*">PROPAGATION_REQUIRED</prop>
                <prop key="update*">PROPAGATION_REQUIRED</prop>
                <prop key="remove*">PROPAGATION_REQUIRED</prop>
                <prop key="*">PROPAGATION_REQUIREID, readOnly</prop>
            </props>
        </property>
    </bean>


    applicationContext-user.xml - 사용자 관리 프로젝트에 트랜잭션을 처리하는 부분

    <bean id="userServiceTarget" class="net.javajigi.user.service.UserServiceImpl">
        <property name="userDAO">
            <ref local="userDAO" />
        </property>
    </bean>

    <bean id="userService" parent="txProxyTemplate">
        <property name="target">
            <ref local="userServiceTarget" />
        </property>
    </bean>


    applicationContext-board.xml - 자료실 게시판에 트랜잭션을 처리하는 부분

    <bean id="boardServiceTarget" class="net.javajigi.board.service.BoardServiceImpl">
        <property name="boardDAO">
            <ref local="boardDAO" />
        </property>
        <property name="boardFileDAO">
            <ref local="boardFileDAO" />
        </property>
    </bean>

    <bean id="boardService" parent="txProxyTemplate">
        <property name="target">
            <ref local="boardServiceTarget" />
        </property>
        <property name="transactionAttributes">
            <props>
                <prop key="add*">PROPAGATION_REQUIRED</prop>
                <prop key="update*">PROPAGATION_REQUIRED</prop>
                <prop key="remove*">PAROPAGATION_REQUIRED</prop>
                
                <!-- findBoardWithView 메소드일 경우 readOnly 속성을 적용하지 않도록 설정하기 위해 재정의 -->
                <prop key="findBoardWithView">PROPAGATION_REQUIRED</prop>

                <prop key="*">PROPAGATION_REQUIRED</prop>
            </props>
        </property>
    </bean>


    Spring 프레임워크에서 선언적으로 트랜잭션을 처리할 때 트랜잭션 속성을 정의하는 방법


PROPAGATION, ISOLATION, readOnly, -Exceptions, +Exceptions
↑                      ↑                ↑                           ↑           
전달 행위(필수)  격리 레벨(선택)  readOnly 유무(선택)  Rollback 규칙(선택)


    빈 설정 파일에서 트랜잭션 속성을 설정할 때 위와 같은 규칙으로 작성하면 된다.
    위 각 항목들에 대하여 살펴보면 다음과 같다.

    * 전달 행위 : 필수 값으로 전달 행위 (Propagation Behavior) 표의 값 중 하나를 사용할 수 있다.
    * 격리 레벨 : 선택 값으로 트랜잭션 격리 레벨 (Isolation Level) 표의 값 중 하나를 사용할 수 있다.
    * readOnly 유무 : 선택 값으로서 실행하는 트랜잭션이 읽기 전용일 경우에 사용 가능하다.
                            일반적으로 트랜잭션 내에서 SELECT 쿼리만을 실행하는 경우이 속성을 사용한다.
    * Rollback 규칙 : Spring 프레임워크 트랜잭션의 디폴트 설정은 RuntimeException 이 발생하는 경우에는 Rollback,
                            CheckedException 이 발생하는 경우에는 Commit 되도록 하고 있다.
                            그러나 트랜잭션의 속성을 지정할 때 Rollback 규칙을 이용하여 디폴트 설정을 변경하는 것이 가능하다.
                            Rollback 규칙에서 마이너스(-)로 시작하는 Exception 에 대해서는 무조건 Rollback,
                            플러스(+)로 시작하는 Exception 에 대해서는 무조건 Commit 되도록 규칙을 변경할 수 있다.

    ex) PROPAGATION_REQUIRED, ISOLATION_SERIALIZABLE, -net.javajigi.user.PasswordMismatchException


4. Spring AOP의 Autoproxying 기능

대규모 프로젝트에서 비즈니스 계층을 담당하는 빈의 숫자가 많을 경우 위와 같이 별도의 빈을 정의해야 하는 작업 또한 짜증나는 작업이 된다. 이와 같은 경우에 Spring AOP의 Autoproxying 기능을 이용하여 트랜잭션을 처리하도록 구현하면 다음과 같다.

    applicationContext-user.xml

    <bean id="userService" class="net.javajigi.user.service.UserServiceImpl">
        <property name="userDAO">
            <ref local="userDAO" />
        </property>
    </bean>


    applicationContext-board.xml

    <bean id="boardService" class="net.javajigi.board.service.BoardServiceImpl">
        <property name="boardDAO">
            <ref local="boardDAO" />
        </property>
        <property name="boardFileDAO">
            <ref local="boardFileDAO" />
        </property>
    </bean>


위와 같이 "userServiceTarget", "boardServiceTarget" 으로 빈의 이름을 변경할 필요가 없다.
아래와 같이 Spring AOP의 Autoproxying 기능을 이용하여 트랜잭션을 처리하도록 설정한다.

    applicationContext-transaction.xml

    <beans>
        <bean id="nameMatchAs" class="org.springframework.transaction.interceptor.NameMatchTransactionAttributeSource">
            <property name="properties">
                <props>
                    <prop key="add*">PROPAGATION_REQUIRED</prop>
                    <prop key="update*">PROPAGATION_REQUIRED</prop>
                    <prop key="remove*">PROPAGATION_REQUIRED</prop>
                    <prop key="findBoardWithView">PROPAGATION_REQUIRED</prop>
                    <prop key="*">PROPAGATION_REQUIRED</prop>
                </props>
            </property>
        </bean>

        <bean id="transactionInterceptor" class="org.springframework.transaction.interceptor.TransactionInterceptor">
            <property name="transactionManager">
                <ref bean="transactionManager" />
            </property>
            <property name="transactionAttributeSource">
                <ref bean="nameMatchAs" />
            </property>
        </bean>

        <bean id="autoProxyCreator" class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
            <property name="interceptorNames">
                <list>
                    <idref bean="loggingAdvice" />
                    <idref bean="emailNotificationThrowsAdvice" />

                    <idref local="transactionInterceptor" />
                </list>
            </property>
            <property name="beanNames">
                <list>
                    <idref bean="boardService" />
                    <idref bean="userService" />
                </list>
            </property>
        </bean>
    </beans>


applicationContext-transaction.xml 을 보면 빈 설정 파일의 빈 이름을 기준으로 Autoproxying을 지원하도록 BeanNameAutoProxyCreator를 사용하고 있다. 또한 BeanNameAutoProxyCreator에 설정되어 있는 각 빈의 메소드와 메소드별 트랜잭션 속성을 정의할 때는 NameMatchTransactionAttributeSource 클래스를 이용하고 있다.
Spring 프레임워크는 NameMatchTransactionAttributeSource 클래스 외에도 MatchAlwaysTransactionAttributeSource, MethodMapTransactionAttributeSource, RuleBasedTransactionAttribute와 같은 클래스들을 지원하고 있다.

Spring 프레임워크의 Autoproxying 기능을 이용하여 트랜잭션을 처리하기 위해서는 애플리케이션의 메소드 이름에 대한 명명규칙이 존재해야 하며, 이 명명규칙을 기반으로 애플리케이션을 개발해야 한다.
명명규칙을 지키지 않았을 경우 일관된 규칙이 없기 때문에 Autoproxying 기능을 이용하기 힘들어진다.

 

출처 : http://kr.blog.yahoo.com/i056695/1030.html?p=3&pm=l&t=1&tc=50&tt=1213170497

[본문링크] Spring 프레임워크 워크북 정리노트 - Chapter5. Spring 트랜잭션
[1]
코멘트(이글의 트랙백 주소:/cafe/tb_receive.php?no=30342
작성자
비밀번호

 

SSISOCommunity

[이전]

Copyright byCopyright ⓒ2005, SSISO Community All Rights Reserved.