3.プログラム的なトランザクション制御

概要

Spring Transactionの最後を飾るのは、プログラム的なトランザクション制御です。

他の2つとの違いは、プログラムでトランザクションを記述する点です。

また、他の2つはAOPを利用してトランザクション管理を行いますが、プログラム的なトランザクション制御では、AOPを使用しません。

この点も違いの一つかと思います。

ただ、プログラムで記述するならば、普通に記述しても同じでは?と思うかもしれません。

しかし、Springのトランザクション管理下におかれる点が違います。

Springの管理下におかれることで、他のトランザクション制御の方法と混在して使用することができます。

基本的に、Springのトランザクション管理と、Spring以外のトランザクション管理を混在して使用すると

rollbackやcommitするタイミングなどに不整合が起きて、うまく動作しない可能性があります。

ですので、すべてSpringトランザクションの管理下に置くようにしましょう。

では、プログラム的トランザクション制御のサンプルを見ていきましょう。

使用サンプル

Spring設定ファイルのサンプル

<?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:aop ="http://www.springframework.org/schema/aop "

xmlns:tx ="http://www.springframework.org/schema/tx "

xmlns:context="http://www.springframework.org/schema/context"

xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsdhttp://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.5.xsd http://www.springframework.org/schema/aop

http://www.springframework.org/schema/aop/spring-aop-2.5.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd ">

<!-- Data Source (例えばPostgres)-->

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">

<property name="driverClassName" value="org.postgresql.Driver"/>

<property name="url" value="jdbc:postgresql://localhost/XXXX" />

<property name="username" value="XXX" />

<property name="password" value="XXX" />

</bean>

<!-- DAO -->

<bean id="testDao" class="dao.TestDaoImpl">

<property name="dataSource" ref="dataSource" />

</bean>

<!-- ビジネス -->

<bean id="testService" class="business.service.TestServiceImpl">

<property name="transactionOperationsRequired" ref="transactionTemplateRequired" />

<property name="testDao" ref="testDao" />

</bean>

<!-- トランザクション管理 -->

<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">

<property name="dataSource" ref="dataSource"/>

</bean>

<!-- トランザクション処理用テンプレートクラス。 -->

<bean id="transactionTemplateRequired" class="org.springframework.transaction.support.TransactionTemplate">

<property name="transactionManager" ref="transactionManager" />

<property name="propagationBehaviorName" value="PROPAGATION_REQUIRED" />

</bean>

</beans>

トランザクションテンプレートを宣言しておき、ビジネスロジックにDIします。

テンプレートに、トランザクションの様々な設定が可能です。

設定できる内容は宣言的トランザクションと同じです。

詳しくは、宣言的トランザクションの記事をご覧ください。

プログラムのサンプル

//setter/getterは記述を省略しています

public class TestServiceImpl {

private TestDao testDao;

private TransactionOperations transactionOperationsRequired;

public void doSomething(String name){

//トランザクションを管理する (返り値が無い場合)

transactionOperationsRequired.execute(new TransactionCallbackWithoutResult() {

//このメソッド内で実行したSQLがトランザクション管理されます。

protected void doInTransactionWithoutResult(TransactionStatus status) {

testDao.insert();

testDao.update();

}

});

}

}

プログラム的トランザクションは、コールバックメソッド内で、処理を記述することになります。

上記のように無名クラスを作成するのが一般的のようです。

TransactionCallbackWithoutResultクラスは、結果を返さないタイプのトランザクション制御クラスです。

この他にも結果を返したい場合は、TransactionCallbackインターフェースを使用すればよいです。

上記のようにプログラム的にトランザクションを記述することで、宣言的トランザクションなどより、

より細かなトランザクション制御ができるようになります。

上記の場合、testDao.insert() か、testDao.update()のいずれかで例外が発生した場合、rollbackすることになります。

TransactionTemplateについて

ちなみにこのクラスは、setterで内部の値を変更しない限り、スレッドセーフです。

他のサイトで紹介している方法は、このクラスもプログラム内でnewしているものがほとんどです。

こういうこともできるということをお見せしたいためにSpring設定ファイルに記述する方法を紹介しました。

ほとんどの場合、propagationやisolationなどの設定は同じなので使い回したくなるはずですが、

プログラム内でTransactionTemplateをnewすると毎回設定しないといけないので面倒です。

また、setterで内部の値を変更してしまう危険性は、上記のように使用するクラス内でインターフェースで受け取ることで

ほぼ回避できるかと思います。

最後に

プログラム的なトランザクションの説明は以上で終了です。

めったにこの方法を使用することはないかと思います。

しかし、知っておいた方が何かあったときにすぐ対応できます。

是非、覚えておきましょう。

【その他】

プログラム的なトランザクションの方法としては、PlatformTransactionManagerを使う方法もあります。

気になる方は調べてみると面白いかと思います。

ここで紹介した方法より、もっとプログラム的です。

Created Date: 2011/01/31