前の記事 で見た宣言的トランザクションを見ていきます。
宣言的トランザクションを使用すると、beginTransaction()、rollback()、commit()が自動で行われるようになるため、何もトランザクションのコードを書く必要が無くなります
ここではサンプルをメインにしてみて行こうと思います。
【DAO】 public interface MemberDao{ List<String> find(String name); } pulic class MemberDaoImpl implements MemberDao { List<String> find(String name){ //...SQLなどの実行 return listNames; } } 【ビジネスロジック】 public interface MemberService{ List<String> find(String name); } //setter/getterは記述を省略しています public class MemberServiceImpl implements MemberService{ private MemberDao memberDao; List<String> find(String name){ return memberDao.find(name); } }
【Spring設定ファイル(AppricationContext.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: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.xsd
http://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.xsd
http://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="memberDao" class="dao.MemberDaoImpl">
<property name="dataSource" ref="dataSource" />
</bean>
<!-- ビジネス -->
<bean id="memberService" class="business.service.MemberServiceImpl">
</bean>
<!-- トランザクション管理 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 宣言的トランザクションの織り込み -->
<aop:config proxy-target-class="false">
<aop:advisor pointcut="execution(* business.service.*(..))" advice-ref="txAdvice" />
</aop:config>
<tx:advice id="txAdvice" >
<tx:attributes>
<tx:method name="find*" read-only="true" />
<tx:method name="*" propagation="REQUIRED" />
</tx:attributes>
</tx:advice>
</beans>
【説明】
DAOとビジネスロジックは、通常のSpringのお作法どおり書いていますので説明は省きます。
ここではfindというメソッドのみを作成しましたが、もっといろいろ追加しても当然OKです!
パッケージbusiness.service 内に存在するクラスのメソッドについて勝手にトランザクションの開始とcommit/rollbackをしています。
では、Springの設定ファイルを中心に見ていきます。
<トランザクション管理クラス(transactionManager)>
このbeanの設定が、トランザクション管理を実際に担当するクラスの設定になります。
bean名(id)は、通常はtransactionManagerにしておきます。
<トランザクションのアドバイス(tx:advice)>
宣言的トランザクションでは、AOP を使用して処理を実現します。
そのため、アドバイスとよばれるAOPの機能を使用します。
ただし、Springではタグ名にtx:をつけて、トランザクション専用のアドバイスという管理になっています。
ここで実は省略が入っています。
どこにもtransactionManagerというbean名が記述されていません。
実は、Springの設定ファイルにこの名前でbeanが設定されていればそれを使用するようになっているので記述を省略できるのです。
tx:methodタグの属性:
name | トランザクション開始・終了の管理をするメソッド名をしていします。 ワイルドカードを使用できます。 |
---|---|
propagation | トランザクション属性を指定します。 トランザクション管理のメソッドがネストしているときに特に役に立ちます。 【設定可能な値】 |
isolation | トランザクションの独立レベルを設定します。 ただし、この設定はDBの仕様に依存するため、使用するDBの仕様をよく確認する必要があります。 【設定可能な値】 - DEFAULT・・DBが提供するデフォルトの独立性レベル。 |
read-only | トランザクションが読み取り専用かどうかを設定します。 |
rollback-for | ここで設定した例外が発生したときにロールバックします。 例外クラスの指定は、カンマ区切りで複数できます。 ロールバックやコミットのタイミングは、nameで指定したメソッドを抜けた後です。 トランザクション管理に指定したメソッドがネストしている場合、一番外側のメソッドを抜けた後です。 |
no-rollback-for | ここで設定した例外が発生したときはコミットします。 例外クラスの指定は、カンマ区切りで複数できます。 |
timeout | トランザクション処理のタイムアウト時間(秒)を指定します。 |
<AOPの織り込み(aop:config)>
これは通常のAOPの設定です。
上記で定義したアドバイスを設定しているだけです。
以下を参照してください。
【サンプルの動作】
サンプルでは、トランザクション管理する対象メソッドとして、find*が設定されています。
設定の再掲:
<tx:method name="find*" read-only="true" />
つまり、find、findTargetなど、メソッド名がfindで始まるものが対象になります。
そしてポイントカットでbusiness.service.*(..)を指定しているので、
MemberServiceImplクラスなどが対象になります。
そして、find*は、read-onlyとなっているため、もし更新SQLが実行されるとエラーになるはずです。
またその下のタグで*が設定されているので、find*に引っかからなかったメソッドはすべてREQUIRED になっています。
つまり、updateTarget, insertTargetなどのメソッドがあれば、トランザクション開始する仕様です。
<tx:method name="*" propagation="REQUIRED" />
【ロールバックの動作】
MemberServiceImplに、以下のメソッドがあったとします。
上記のSpringの設定どおり、REQUIRED になるため、例外が発生するとロールバックします。
これをもう少し詳しく見てみます。
pulic void insertTarget(Member member){
//・・・処理
}
pulic void updateTarget(Member member){
insertTarget(member)
//・・・その他のDB処理
}
トランザクション管理のメソッドがネストしているのが分かるでしょうか?
この場合は、どのようにロールバックするでしょうか?
①insertTargetメソッド内で例外が発生した場合
insertTargetメソッドを抜け出した後にロールバックします。
REQUIRED の場合は、イメージとしてはinsertTargetメソッドが以下のように書き換えられた感じです。
try{
transaction.begin();
insertTarget(member);
transaction.commit();
}catch(Exception e){
transaction.rollback();
}
②updateTargetメソッド内で例外が発生した場合
updateTargetメソッドを抜け出した後にロールバックします。
トランザクション属性にREQUIRED を指定した場合、イメージとしては以下のような感じです。
try{
transaction.begin();
updateTarget(member);
transaction.commit();
}catch(Exception e){
transaction.rollback();
}
※insertTarget()にも当然、トランザクションの処理が織り込まれていますが、
すでにupdateTarget()の方でトランザクションを開始していますので、insertTarget()に織り込まれた
トランザクション開始は無視されます。
もし、トランザクション属性にNESTEDを指定していれば、ネストしたトランザクションがinsertTarget()でも
開始されるはずです。
こうして、methodタグで指定したメソッド毎にトランザクションの開始・終了の設定ができます。
これが宣言的トランザクションです。
ほぼ、これだけで十分だと思います。
その他の機能は、別の記事で書いていこうと思います。
以下の記事を参考にしてみてください。
参照:
・トップ