「Spring」 DataSourceTransactionManager での宣言的トランザクション
DataSourceTransactionManager で宣言的トランザクションを使ってみたので、メモしておきます。
DataSourceTransactionManager は単一のデータソースに対するトランザクションマネージャになります。
・DataSourceTransactionManager (Spring Framework 3.2.13.RELEASE API)
< http://docs.spring.io/spring/docs/3.2.x/javadoc-api/org/springframework/jdbc/datasource/DataSourceTransactionManager.html >
宣言的トランザクションには、Bean 定義ファイルを使用するのと、アノテーションでやる方法がありますが、今回はそれぞれ試してみました。
ドキュメントは以下あたりです。
・Spring Framework Reference Documentation
< http://docs.spring.io/spring/docs/3.2.13.RELEASE/spring-framework-reference/htmlsingle/#transaction >
1. Bean 定義ファイルを使用する方法
以下の感じで DAO クラス、Main クラス、Bean 定義ファイルを作成することでできます。
■ SampleDAO.java
package com.example.datasource; import java.util.List; import java.util.Map; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Component; @Component public class SampleDAO { @Autowired JdbcTemplate jdbcTemplate; public void select() { List<Map<String, Object>> result = jdbcTemplate.queryForList("select * from t1"); for (Map<String, Object> r : result) { System.out.println(r.get("id").toString() + " : " + r.get("name").toString()); } } public void insert() { int result = jdbcTemplate.update("insert into t1 values (3, 'oro')"); } // ( *1 ) // public void insert() throws DAOException { // throw new DAOException(); // } }
■ Main.java
package com.example.datasource; import org.springframework.context.support.ClassPathXmlApplicationContext; public class Main { public static void main(String[] args) { try (ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("dataSource.xml")) { SampleDAO dao = context.getBean(SampleDAO.class); dao.insert(); //(*2) //try { // dao.insert(); //} catch (DAOException e) { // e.printStackTrace(); //} dao.select(); } } }
■ dataSource.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:context="http://www.springframework.org/schema/context" 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-3.1.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd"> <bean id="sampleDAO" class="com.example.datasource.SampleDAO" /> <context:property-placeholder location="classpath:jdbc.properties"/> <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"> <property name="driverClassName" value="${driver}" /> <property name="url" value="${url}" /> <property name="username" value="${username}" /> <property name="password" value="${password}" /> </bean> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="dataSource" /> </bean> <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean> <tx:advice id="txAdvice" transaction-manager="txManager"> <tx:attributes> <tx:method name="insert*" propagation="REQUIRED" isolation="READ_COMMITTED" read-only="false" rollback-for="com.example.datasource.DAOException"/> </tx:attributes> </tx:advice> <aop:config> <aop:advisor advice-ref="txAdvice" pointcut="execution(* com.example.datasource.SampleDAO.*(..))" /> </aop:config> <context:annotation-config /> <context:component-scan base-package="com.example.datasource" /> </beans>
今回は SampleDAO の insert メソッドをトランザクションの対象にしてます ( propagation 等のトランザクション定義情報は適当です )。
ロールバック対象例外 rollback-for に DAOException を設定しているので、上記のコメントアウト (*1)、(*2) を外してやるとちゃんとロールバックされるはずです。
2. アノテーションを使用する方法
■ SampleDAO.java
package com.example.datasource; import java.util.List; import java.util.Map; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; @Component public class SampleDAO { @Autowired JdbcTemplate jdbcTemplate; public void select() { List<Map<String, Object>> result = jdbcTemplate.queryForList("select * from t1"); for (Map<String, Object> r : result) { System.out.println(r.get("id").toString() + " : " + r.get("name").toString()); } } @Transactional public void insert() { int result = jdbcTemplate.update("insert into t1 values (3, 'oro')"); } // @Transactional(rollbackFor=DAOException.class) // public void insert() throws DAOException { // throw new DAOException(); // } }
■ Main.java
上記と同様なので割愛
■ dataSource.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:context="http://www.springframework.org/schema/context" 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-3.1.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd"> <bean id="sampleDAO" class="com.example.datasource.SampleDAO" /> <context:property-placeholder location="classpath:jdbc.properties"/> <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"> <property name="driverClassName" value="${driver}" /> <property name="url" value="${url}" /> <property name="username" value="${username}" /> <property name="password" value="${password}" /> </bean> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="dataSource" /> </bean> <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean> <tx:annotation-driven transaction-manager="txManager"/> <context:annotation-config /> <context:component-scan base-package="com.example.datasource" /> </beans>
アノテーションは @Transactional を使用します。トランザクション定義情報も Bean 定義ファイルと同様に設定できますが、上記では設定してません。この場合はデフォルト値が使われるっぽいです。
・Transactional (Spring Framework 3.2.13.RELEASE API)
< http://docs.spring.io/spring/docs/3.2.x/javadoc-api/org/springframework/transaction/annotation/Transactional.html >
Bean 定義ファイルでは
とりあえず上記でトランザクションが有効になるはずです。
で、DataSourceTransactionManager は log4j でログ吐くコードが入っているので、log4j.properties を以下の感じで作ってやるとトランザクション関連のログが出力されます ( Maven でやってる場合は src/main/resources 配下においてやってください )。
log4j.appender.stderr=org.apache.log4j.ConsoleAppender log4j.appender.stderr.Target=System.err log4j.appender.stderr.layout=org.apache.log4j.PatternLayout log4j.appender.stderr.layout.ConversionPattern=%d %5p %c{1} - %m%n #log4j.rootLogger=DEBUG,stderr log4j.logger.org.springframework.jdbc.datasource.DataSourceTransactionManager=DEBUG,stderr
Spring のトランザクションマネージャには他にも HibernateTransactionManager やら JmsTransactionManager、JtaTransactionManager などなど色々あります。基本的に上記と同じ要領だと思ってますが、また今度試してみたいと思います ( まずは分散トランザクションにも対応している JtaTransactionManager からかな・・・ )。
以上です。
[ 環境情報 ]
Windows 7 SP1
Java SE 7 Update 51
Spring Framework 3.2.13
PostgreSQL 9.0.4
PostgreSQL JDBC Driver 9.0-801