Whiteship's Note


Spring 트랜잭션 처리 2-1. XML based Declarative

Spring/Chapter 9 : 2007.05.05 23:54


Spring의 선언적 트랜잭션 관리 기법 중에서 XML 설정 내용을 사용하는 방법을 살펴 봅니다.

다른 방법으로는 어노테이션을 사용하는 방법이 있습니다. 이것은 Spring 트랜잭션 관리가 Spring AOP(그중에서도 Autoproxing)를 사용하고 있기 때문에 Spring AOP를 구현하는 두 가지 방법과 나란히 두 가지 방법을 마련한 것 같습니다.

먼저 트랜잭션 설정을 하기 위한 네임스페이스가 필요합니다. 다음과 같은 XML 설정 탬플릿을 사용하면 됩니다.
<?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:util="http://www.springframework.org/schema/util"
       xmlns:p="http://www.springframework.org/schema/p"
       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/util http://www.springframework.org/schema/util/spring-util-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"
default-autowire="byName">

//여기에 기타 bean 설정을 넣어 줍니다.

</beans>

그리고 일반 bean들을 등록한 뒤 "트랜잭션 Advice"로 트랜잭션 처리할 메소드의 이름과 트랜잭션 특성을 지정해 주고 "트랜잭션 Advisor"로 방금 만든 Advice와 이 Advice를 적용한 Pointcut을 묶어 줍니다.

    <bean id="memberService" class="com.bookbuying.member.service.MemberServiceImplDeclarativeTransactionManagement">
        <property name="memberDao" ref="memberDao" />
    </bean>

    <bean id="memberDao" class="com.bookbuying.member.dao.MemberDaoImpleWIthSpringTransaction">
        <property name="sessionFactory" ref="sessionFactory" />
    </bean>

    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <tx:attributes>
            <tx:method name="add*" propagation="REQUIRED" />
        </tx:attributes>
    </tx:advice>

    <aop:config>
        <aop:pointcut id="memberServiceOperation"
            expression="execution(* com.bookbuying.member.service.MemberService.*(..))" />
        <aop:advisor advice-ref="txAdvice"
            pointcut-ref="memberServiceOperation" />
    </aop:config>

설정 파일의 내용은 좀 복잡해 졌지만 자바 코드는 매우 깔끔해 졌습니다. 더이상 Business Layer에 전~혀 트랜잭션 관련 코드가 들어있지 않습니다.
    private MemberDao memberDao;

    public void setMemberDao(MemberDao memberDao) {
        this.memberDao = memberDao;
    }

    public void add(Member member) throws SQLException {
        memberDao.add(member);
        //TODO 예외 발생시키기
        TransactionTestingUtil.generateExceptionMethod();
    }

Dao 구현체는 이전에 만들어둔 클래스를 사용하였습니다. 테스트 코드 역시 이전 글들에서 사용한 것을 사용했으며 제대로 동작하는 것을 확인했습니다.


신고
top


Spring 트랜잭션 처리 1. Programmtic

Spring/Chapter 9 : 2007.05.04 20:45


참조 : Spring 프레임워크 워크북, 9.6. Programmatic transaction management (1)

레퍼런스와 워크북에도 나오지만 프로그래밍 적인 트랜잭션 처리 방법은 크게 두 가지가 있습니다.

1. PlatformTransactionManager, TransactionStatus, TransactionDefinition을 사용하는 방법

(1)TransactionManager를 만들 때는 사용하는 트랜잭션 자원에 따라 만드는 방법이 다릅니다. (2)그리고 TransactionManager로 부터 getTransaction을 사용하여 트랜잭션을 생성하게 되는데 이 때 TransactionStatus라는 객체를 받게 됩니다. (3)롤백과 커밋은 TransactionManager를 사용하며 이 때 Status객체를 넘겨줘야 합니다.

서비스 계층의 구현된 코드를 보면서 위의 내용을 살펴보겠습니다.

public class MemberServiceImplWithSpringTransaction implements MemberService {

    private MemberDao memberDao;

    private PlatformTransactionManager transactionManager;

    public void setMemberDao(MemberDao memberDao) {
        this.memberDao = memberDao;
    }

    public void setTransactionManager(PlatformTransactionManager transactionManager) {
        this.transactionManager = transactionManager;
    }

    public void add(Member member) throws SQLException {
        DefaultTransactionDefinition def = new DefaultTransactionDefinition();
        def.setName("멤버 추가하는 트랜잭션");
        def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
        TransactionStatus status = transactionManager.getTransaction(def); //(2)
        try {
            memberDao.add(member);
            //TODO 예외 발생
            TransactionTestingUtil.generateExceptionMethod();
            transactionManager.commit(status); //(3)
        }
        catch (MyException e) {
            System.out.println(def.getName() + " 롤백합니다.");
            transactionManager.rollback(status); //(3)
            throw e;
        }
    }

}

TransactionManager는 HibernateTransactionManager 를 사용하고 있습니다. XML 설정을 보면 다음과 같습니다.

    <bean id="memberService" class="com.bookbuying.member.service.MemberServiceImplWithSpringTransaction">
        <property name="memberDao" ref="memberDao" />
        <property name="transactionManager" ref="transactionManager" />
    </bean>

    <bean id="memberDao" class="com.bookbuying.member.dao.MemberDaoImpleWIthSpringTransaction">
        <property name="sessionFactory" ref="sessionFactory" />
    </bean>

    <bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean" autowire="no">
        <property name="dataSource" ref="dataSource" />
        <property name="annotatedClasses" ref="annotatedClasses" />
        <property name="hibernateProperties">
            <props>
                <!-- 지금 사용하고 있는 데이터베에스에 최적화 된 SQL을 생성하기 위해서
                      현재 데이터베이스에 해당하는 Hibernate dialect 클래스 명 -->
                <prop key="hibernate.dialect">${hibernate.dialect}</prop>

                <!--  콘솔 창에 사용하는 모든 SQL문을 출력할지를 선택  -->
                <prop key="hibernate.show_sql">true</prop>

                <!-- DB Schema에 변경사항이 발생한 경우 자동으로 수정  -->
                <prop key="hibernate.hbm2ddl.auto">update</prop>

                <!-- 성능 튜닝에 도움이 되는 유용한 통계를 제공  -->
                <prop key=" hibernate.generate_statistics">true</prop>

                <!-- 자동 커밋이 되는 것을 방지 -->
                <prop key="hibernate.connection.autocommit">false</prop>

                <!-- "Current" Session의 Scope 설정.<jta/thread/managed/custom> -->
                <prop key="hibernate.current_session_context_class">thread</prop>
            </props>
        </property>
    </bean>

    <util:list id="annotatedClasses">
        <value>com.bookbuying.domain.Member</value>
    </util:list>

    <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager" autowire="no">
        <property name="sessionFactory" ref="sessionFactory" />
    </bean>

주석은 친절한 하이버네이트 찬욱군이 달아 놓았습니다. Hibernate를 사용하여 DAO쪽 구현을 했습니다. 여기서 Session에 주목할 필요가 있습니다. 그건 다음 글에서 살펴보겠습니다.

public class MemberDaoImpleWIthSpringTransaction implements MemberDao{

    private SessionFactory sessionFactory;

    public void setSessionFactory(SessionFactory sessionFactory) {
        this.sessionFactory = sessionFactory;
    }

    public void add(Member member) {
        Session session = sessionFactory.getCurrentSession();
        session.save(member);
    }
}

신고
top


JDBC 기반 트랜잭션 처리 2. Business Layer에서 책임

Spring/Chapter 9 : 2007.05.04 20:29


참조 : Spring 프레임워크 워크북

이번에는 DAO 계층이 아닌 Service 계층으로 트랜잭션 책임을 다시 가져왔습니다. 따라서 서비스 계층이 이 전글에 비하면 좀 더 복잡해 졌습니다. 게다가 쌩 JDBC를 사용하고, 거기다 트랜잭션 처리도 AOP 사용해서 모듈화 하지 않았기 때문에 코드는 다음과 같이 다소 복잡합니다.

public class MemberServiceImplTransactionInBusiness implements MemberService{

    private MemberDao memberDao;

    private DataSource dataSource;

    public void setDataSource(DataSource dataSource) {
        this.dataSource = dataSource;
    }

    public void setMemberDao(MemberDao memberDao) {
        this.memberDao = memberDao;
    }

    public void add(Member member) throws SQLException {

        Connection con = null;
        try {
            con = dataSource.getConnection();
            con.setAutoCommit(false);
            memberDao.add(con, member);
            //TODO 예외발생
            TransactionTestingUtil.generateSQLExceptionMethod();
            con.commit();
        }
        catch (SQLException e) {
            if(con != null)
                con.rollback();
            throw e;
        }
        finally {
            if(con != null)
                con.close();
        }
    }

}

add()메소드에서 해야할 일은 딱 두 줄(파란색)임에도 불구하고 여러 줄의 코드가 정신없이 널려있습니다. DAO 코드를 보겠습니다.

public class MemberDaoJdbcTransactionInBusiness implements MemberDao {

    public void add(Member member) {
        throw new UnsupportedOperationException();
    }

    public void add(Connection con, Member member) throws SQLException {
        StringBuilder addMemberQuery = new StringBuilder();
        addMemberQuery.append("INSERT INTO Member(id, password, name, email) ");
        addMemberQuery.append("VALUES (?, ?, ?, ?)");

        try {
            PreparedStatement pstmt = con.prepareStatement(addMemberQuery.toString());
            pstmt.setString(1, "whiteship3");
            pstmt.setString(2, "pass");
            pstmt.setString(3, "기선");
            pstmt.setString(4, "keesun3@email.com");
            pstmt.executeUpdate();
        }
        catch (SQLException e) {
            throw e;
        }
    }

}

JDBC 코딩이 별로 재미도 없고 복잡합니다. 서비스 계층에서 사용하던 connection 객체를 그대로 이어 받아서 사용합니다. 그리고 만약 복잡한 SQL을 사용했을 떄 DB가 바껴버리면 그 복잡한 SQL들을 다 어떻게 관리할지 걱정이 됩니다.

테스트코드는 이전 글과 동일합니다. Spring 설정파일은 다음과 같습니다.

    <bean id="memberService" class="com.bookbuying.member.service.MemberServiceImplTransactionInBusiness">
        <property name="dataSource" ref="dataSource" />
        <property name="memberDao" ref="memberDao" />
    </bean>

    <bean id="memberDao" class="com.bookbuying.member.dao.MemberDaoJdbcTransactionInBusiness" />

    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="${db.driver}"/>
        <property name="jdbcUrl" value="${db.url}"/>
        <property name="user" value="${db.username}"/>
        <property name="password" value="${db.password}"/>
    </bean>

다음 글에서는 Spring의 Transaction 관련 주요 API들(TransactionDefinition, TransactionStatus, PlatformTransactionManager)을 사용하여 구현하겠습니다.
신고
top


JDBC 기반 트랜잭션 처리 1. Persistence Layer에서 책임

Spring/Chapter 9 : 2007.05.04 13:06


참조 : Spring 프레임워크 워크북

Spring 트랜잭션 처리를 예제 코드로 살펴보기 위해 먼저 JDBC 기반의 트랜잭션 처리의 불편함을 몸소 체험할 수 있는 코드를 작성했습니다.

트랜잭션 처리는 비즈니스 계층에서 해야겠죠. 하지만 왠지 트랜잭션! 이라고 하면 DB랑 연관이 있는 것 같아서 왠지 DAO 계층에서 처리해야 될 것만 같은 느낌을 받았었습니다. 하지만 생각해 보면 DAO는 그냥 DB에 접근하는 CRUD 하는 SQL을 날릴 뿐이고 진짜 고객이 원하는 작업의 단위는 Service 계층의 메소드 단위일 것이고 그 메소드 하나에는 여러 DAO 를 사용하여 Logical Unit of Works(=transaction)을 구현할 것입니다.

Anyway.. 스프링 워크북에 나온대로 퍼시스턴스 계층에서 책임지도록 코딩해 보았습니다.

public class MemberServiceImplTransactionInPersistence implements MemberService {

    private MemberDao memberDao;

    public void setMemberDao(MemberDao memberDao) {
        this.memberDao = memberDao;
    }

    public void add(Member member) throws SQLException {
        memberDao.add(member);
    }

}

서비스 계층은 위와 같이 단순합니다. 모든 책임이 memberDao의 add에 있고 사실 여기있는 add메소드에서 memberDao.add(member); 만 호출합니다. 그 안에는 아래와 같이 다른 작업과 트랜잭션처리도 담당합니다.

public class MemberDaoJdbcTransactionInPersistence implements MemberDao {

    private DataSource dataSource;

    public void setDataSource(DataSource dataSource) {
        this.dataSource = dataSource;
    }

    public void add(Member member) throws SQLException {
        Connection con = null;
        PreparedStatement pstmt = null;
        try {
            con = dataSource.getConnection();
            con.setAutoCommit(false);

            StringBuilder addMemberQuery = new StringBuilder();
            addMemberQuery.append("INSERT INTO Member(id, password, name, email) ");
            addMemberQuery.append("VALUES (?, ?, ?, ?)");

            pstmt = con.prepareStatement(addMemberQuery.toString());
            pstmt.setString(1, "whiteship3");
            pstmt.setString(2, "pass");
            pstmt.setString(3, "기선");
            pstmt.setString(4, "keesun3@email.com");

            pstmt.executeUpdate();

            //TODO 예외 발생하는 코드
            TransactionTestingUtil.generateSQLExceptionMethod();

            con.commit();
        }
        catch (SQLException e) {
            if(con != null)
                con.rollback();
            throw e;
        }
        finally {
            if(pstmt != null)
                pstmt.close();
            if(con != null)
                con.close();
        }
    }

    public void add(Connection con, Member member) {
        throw new UnsupportedOperationException();
    }
}

와오~ DAO 열라 복잡합니다. 할 일은 파란 색 코드 두 줄입니다. 벌써 부터 이상합니다. DAO 계층이 서비스 계층 코드에서 할 일(예외 발생 부분) 까지 포함하게 됐습니다. 이건 마치 DAO와 서비스 계층이 서로 바뀐 것 같은 모양입니다.

테스트 코드는 아래와 같습니다. 예외를 던지게 해뒀기 때문에 예외가 발생했으면 제대로 동작한 것이고 예외를 안던지면 커밋된 것으로 볼 수 있습니다.

    @Test
    public void testRollBackTransaction() {
        Member member = getMember();
        try {
            memberService.add(member);
            fail();
        }
        catch (SQLException e) {
            e.printStackTrace();
        }
    }

bean 설정은 다음과 같습니다.

    <!-- jdbc transaction in persistence -->
    <bean id="memberService" class="com.bookbuying.member.service.MemberServiceImplTransactionInPersistence">
        <property name="memberDao" ref="memberDao" />
    </bean>

    <bean id="memberDao" class="com.bookbuying.member.dao.MemberDaoJdbcTransactionInPersistence">
        <property name="dataSource" ref="dataSource" />
    </bean>

    <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="locations">
            <list>
                <value>classpath:database.properties</value>
            </list>
        </property>
    </bean>

    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="${db.driver}"/>
        <property name="jdbcUrl" value="${db.url}"/>
        <property name="user" value="${db.username}"/>
        <property name="password" value="${db.password}"/>
    </bean>


신고
top


레퍼런스 8, 9장에 오타

Spring/Chapter 9 : 2007.04.16 12:44


굉장히 사소한거라 이슈 트래커에 등록을 할까 말까 망설이고 있는데 까먹기 전에 블로그에라도 정리해 두기 위해서 씁니다.

8장에 오타 :: an 이 연달아 두개
사용자 삽입 이미지

9장에 오타 :: 따옴표 랑 instance 오타
사용자 삽입 이미지


신고
top


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







티스토리 툴바