[spring]10.3 Understanding the Spring Framework transaction abstraction

10.3 Understanding the Spring Framework transaction abstraction

Springのトランザクション管理における中心概念は、「TransactionStrategy」である。具体的にはorg.springframework.transaction.PlatformTransactionManagerを指す。


public interface PlatformTransactionManager {
TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException;
void commit(TransactionStatus status) throws TransactionException;
void rollback(TransactionStatus status) throws TransactionException;
}

PlatformTransactionManagerはSPIであり、かつ、ソースコードトランザクション制御する場合はAPIになる。PlatformTransactionManagerはインタフェースなので、簡単にモックに差し替えることができる。PlatformTransactionManagerは(アプリケーションでJTAを使う場合とは異なり)JNDIルックアップは不要。PlatformTransactionManagerは他のBeanと同様にSpringIOCコンテナを使って定義できるので簡単にルックアップできる。なのでトランザクショナルなコードはJTAを直接使っている場合と比べて、ずっとテストしやすい。

getTransactionメソッドは、引数TransactionDefinitionに対応するTransactionStatusオブジェクトを返す。TransactionStatusは新規のトランザクションもしくはすでに開始されているトランザクション*1を表す。TransactionStatusはJTAのように実行スレッドと関連付けられる。

TransactionDefinitionインタフェースは以下を定義する。

TransactionStatusインタフェースは、以下のような定義になっており、トランザクションの状態確認や制御をすることができる。


public interface TransactionStatus extends SavepointManager {
boolean isNewTransaction();
boolean hasSavepoint();
void setRollbackOnly();
boolean isRollbackOnly();
void flush();
boolean isCompleted();
}

宣言的トランザクションでも、プログラムでトランザクション制御する場合でも、適切なPlatformTransactionManagerを定義する必要がある。普通はSpringIOCを用いてPlatformTransactionManagerを定義する。PlatformTransactionManagerの実装クラスは、JDBCJTAHibernateなど制御対象ごとに定義される。次の例はJDBCの場合の定義例である。

・データソース


<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="${jdbc.driverClassName}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</bean>

・PlatformTransactionManager


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


もしJTAを使って制御する場合は、代わりに以下のように記述する。


<?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:jee="http://www.springframework.org/schema/jee"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/jee
">http://www.springframework.org/schema/jee/spring-jee-3.0.xsd">

<jee:jndi-lookup id="dataSource" jndi-name="jdbc/jpetstore"/>
<bean id="txManager" class="org.springframework.transaction.jta.JtaTransactionManager" />
<!-- other <bean/> definitions here -->
</beans>

JTAはグローバルトランザクションの機構なので、個別のデータソースをJtaTransactionManagerに紐付ける必要はない。

以下はHibernateの場合の定義例。


<!--LocalSessionFactoryBean : Hibernate Sessionインスタンスを取得するためのBean. -->
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="mappingResources">
<list>
<value>org/springframework/samples/petclinic/hibernate/petclinic.hbm.xml</value>
</list>
</property>
<property name="hibernateProperties">
<value>
hibernate.dialect=${hibernate.dialect}
</value>
</property>
</bean>

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

Hibernateの場合もJTAトランザクションは以下で動かす場合は、


<bean id="txManager" class="org.springframework.transaction.jta.JtaTransactionManager"/>

の定義で良い。

どのような定義であってもアプリケーションのソースコードを変更する必要はない。環境がローカルからグローバルトランザクションに変わっても、設定を変えるだけで良い。

*1:コールスタックに乗っている