7. トランザクション管理 2
2005.09.20 株式会社四次元データ 木虎直樹
7.1. BeanNameAutoProxyCreator による宣言的トランザクション管理
前章で
org.springframework.transaction.interceptor.TransactionProxyFactoryBean
を使用して宣言的トランザクション管理を行うことができるようになりましたが同様の設定を行いたいにもかかわらず Facade や DAO となるクラスごとにトランザクションの振る舞いなどを設定するのは煩雑です。そのような際に便利なクラスが Spring には用意されています。org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator
です。このクラスを使用すれば、たとえば指定したクラスの "update" で始まるメソッドには、トランザクションの振る舞いとしてすべて PROPAGATION_REQUIRED を指定するというようなことが簡単にできるようになります。BeanNameAutoProxyCreator
で設定しなければならないプロパティは以下の 2つです。
- interceptorNames
- beanNames
beanNames はその名前からわかりますが、トランザクション管理対象となる Bean の名前を指定します。interceptorNames には
org.aopalliance.intercept.Interceptor
を実装したクラスを指定します。AOP を学習していない今は、トランザクション管理を行うには Bean 定義ファイルで設定したorg.springframework.transaction.interceptor.TransactionInterceptor
の名前を指定するということを理解するだけで十分です。その TransactionInterceptor ですが、以下のプロパティを指定する必要があります。
- transactionManager
- transactionAttributeSource
transactionManager については前章で出てきたため説明の必要はないでしょう。transactionAttributeSource には
org.springframework.transaction.interceptor.TransactionAttributeSource
を実装したクラスを指定します。TransactionAttributeSource
はどのクラスのどのメソッドにどのようなトランザクション管理を行うのかを指定します。TransactionAttributeSource
の具象クラスには以下の 3つのクラスのうちいずれかを指定します。
org.springframework.transaction.interceptor.MatchAlwaysTransactionAttributeSource
org.springframework.transaction.interceptor.NameMatchTransactionAttributeSource
org.springframework.transaction.interceptor.MethodMapTransactionAttributeSource
MatchAlwaysTransactionAttributeSource
- すべてのメソッドを transactionAttribute プロパティで指定された属性に基づきトランザクショナルに実行します。 以下の使用例ではトランザクション属性に
PROPAGATION_REQUIRED
を指定しています (実はデフォルトでPROPAGATION_REQUIRED
が適用されます)。<bean id="txAttribute" class="org.springframework.transaction.interceptor.MatchAlwaysTransactionAttributeSource"> <property name="transactionAttribute"><value>PROPAGATION_REQUIRED</value></property> </bean>NameMatchTransactionAttributeSource
- 指定された名前を持つメソッドを指定された属性に基づきトランザクショナルに実行します。メソッド名とトランザクション属性は
java.util.Properties
型の properties プロパティで指定します。前章で説明したorg.springframework.transaction.interceptor.TransactionProxyFactoryBean
と同様にキーとなる値にメソッド名を、キーに対応する値にトランザクション属性を指定します。メソッド名にワイルドカード "*" を使用することもできます。 以下の使用例では insert で始まるメソッドにはトランザクション属性としてPROPAGATION_REQUIRED
を指定し、それ以外の文字列で始まるメソッドにはPROPAGATION_REQUIRED,readOnly
を指定しています。<bean id="txAttribute" class="org.springframework.transaction.interceptor.NameMatchTransactionAttributeSource"> <property name="properties"> <props> <prop key="insert*">PROPAGATION_REQUIRED</prop> <prop key="*">PROPAGATION_REQUIRED,readOnly</prop> </props> </property> </bean>MatchAlwaysTransactionAttributeSource
- 指定されたクラスの指定された名前を持つメソッドを指定された属性に基づきトランザクショナルに実行します。クラス名とメソッド名、トランザクション属性は
java.util.Map
型の methodMap プロパティで指定します。Map のキー値に完全限定名で指定したクラス名とメソッド名を "." ドットでつないだ値を指定します。メソッド名にはNameMatchTransactionAttributeSource
と同様ワイルドカード "*" を使用することができます。Map のキーに対応する値にトランザクション属性を指定します。 以下の使用例ではcom.techscore.spring.PersonManager
クラスの insert で始まるメソッドにはトランザクション属性としてPROPAGATION_REQUIRED
を指定し、com.techscore.spring.PersonManager
クラスのそれ以外の文字列で始まるメソッドにはPROPAGATION_REQUIRED,readOnly
を指定しています。<bean id="txAttribute" class="org.springframework.transaction.interceptor.MethodMapTransactionAttributeSource"> <property name="methodMap"> <map> <entry key="com.techscore.spring.PersonManager.insert*"> <value>PROPAGATION_REQUIRED</value> </entry> <entry key="com.techscore.spring.PersonManager.*"> <value>PROPAGATION_REQUIRED,readOnly</value> </entry> </map> </property> </bean>最後に
<beans> <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> ...(略)... </bean> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource"><ref local="dataSource"/></property> </bean> <bean id="txAttribute" class="org.springframework.transaction.interceptor.MatchAlwaysTransactionAttributeSource"> <property name="transactionAttribute"><value>PROPAGATION_REQUIRED</value></property> </bean> <bean id="txInterceptor" class="org.springframework.transaction.interceptor.TransactionInterceptor"> <property name="transactionManager"><ref bean="transactionManager"/></property> <property name="transactionAttributeSource"><ref bean="txAttribute"/></property> </bean> <bean id="debug" class="org.springframework.aop.interceptor.DebugInterceptor"/> <bean id="autoProxyCreator" class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator"> <property name="interceptorNames"> <list> <value>txInterceptor</value> <value>debug</value> </list> </property> <property name="beanNames"> <list> <value>personManager</value> <value>companyManager</value> </list> </property> </bean> <bean id="personManager" class="com.techscore.spring.PersonManagerImpl"> ...(略)... </bean> <bean id="companyManager" class="com.techscore.spring.CompanyManagerImpl"> ...(略)... </bean> </beans>
BeanNameAutoProxyCreator
の interceptorNames, beanNames プロパティを指定するときに ref 要素を使用していないことに注意してください。Bean をコンテナから取り出すには以下のようにします。PersonManager manager = (PersonManager) context.getBean("personManager");
実習課題 1
6章の実習課題 1 を改良しなさい。
org.springframework.transaction.interceptor.TransactionProxyFactoryBean
を使用すること