原文地址:http://tom-duan.javaeye.com/blog/147594
JOTM(Java Open Transaction Manager)是ObjectWeb的一個開源JTA實(shí)現(xiàn),本身也是開源應(yīng)用程序服務(wù)器JOnAS(Java Open Application Server)的一部分,為其提供JTA分布式事務(wù)的功能。Spring對JOTM提供了較好的支持,提供了一個org.springframework.transaction.jta.JotmFactoryBean的支持類,在Spring2.0中也包含了JOTM相關(guān)的一些library。
jotm的下載地址為http://jotm.objectweb.org,最新版本為2.0.10.
下載完成后解壓縮,然后打開jotm下面conf文件夾,拷貝carol.properties文件到classpath中,并修改這個文件如下
carol.properties
- # do not use CAROL JNDI wrapper
- carol.start.jndi=false
-
- # do not start a name server
- carol.start.ns=false
-
- # Naming Factory
- carol.jndi.java.naming.factory.url.pkgs=org.apache.naming
# do not use CAROL JNDI wrapper
carol.start.jndi=false
# do not start a name server
carol.start.ns=false
# Naming Factory
carol.jndi.java.naming.factory.url.pkgs=org.apache.naming
上面配置文件的目的是不使用JNDI的方式來加載JOTM的配置,當(dāng)然也可以根據(jù)需要選擇其它的一些配置,例如JTOM所提供的默認(rèn)配置。
然后開始在Spring上下文中配置JOTM,在classpath中建立一個ApplicationContext-jotm.xml,配置如下
ApplicationContext-jotm.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"
- xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
-
- <bean id="jotm" class="org.springframework.transaction.jta.JotmFactoryBean"/>
-
- <bean id="txManager" class="org.springframework.transaction.jta.JtaTransactionManager">
- <property name="userTransaction" ref="jotm" />
- </bean>
-
- <bean id="ds1" class="org.enhydra.jdbc.pool.StandardXAPoolDataSource" destroy-method="shutdown">
- <property name="dataSource">
- <bean class="org.enhydra.jdbc.standard.StandardXADataSource" destroy-method="shutdown">
- <property name="transactionManager" ref="jotm" />
- <property name="driverName" value="com.mysql.jdbc.Driver" />
- <property name="url" value="jdbc:MySQL://localhost:3306/test" />
- </bean>
- </property>
- <property name="user" value="root" />
- <property name="password" value="admin" />
- </bean>
-
- <bean id="ds2" class="org.enhydra.jdbc.pool.StandardXAPoolDataSource" destroy-method="shutdown">
- <property name="dataSource">
- <bean class="org.enhydra.jdbc.standard.StandardXADataSource" destroy-method="shutdown">
- <property name="transactionManager" ref="jotm" />
- <property name="driverName" value="com.mysql.jdbc.Driver" />
- <property name="url" value="jdbc:MySQL://localhost:3306/test2" />
- </bean>
- </property>
- <property name="user" value="root" />
- <property name="password" value="admin" />
- </bean>
-
- <bean id="template1" class="org.springframework.jdbc.core.JdbcTemplate">
- <property name="dataSource" ref="ds1" />
- </bean>
-
- <bean id="template2" class="org.springframework.jdbc.core.JdbcTemplate">
- <property name="dataSource" ref="ds2" />
- </bean>
-
- <bean id="dao1" class="com.xa.dao.UserDao1">
- <property name="jdbcTemplate">
- <ref bean="template1"></ref>
- </property>
- </bean>
-
- <bean id="dao2" class="com.xa.dao.UserDao2">
- <property name="jdbcTemplate">
- <ref bean="template2"></ref>
- </property>
- </bean>
-
- <bean id="userServiceTarget" class="com.xa.service.UserServiceImpl">
- <property name="dao1" ref="dao1"/>
- <property name="dao2" ref="dao2"/>
- </bean>
-
-
- <bean id="userTest" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
- <property name="transactionManager">
- <ref bean="txManager"/>
- </property>
- <property name="target">
- <ref bean="userServiceTarget"/>
- </property>
- <property name="transactionAttributes">
- <props>
- <prop key="insert*">PROPAGATION_REQUIRED,-Exception</prop>
- </props>
- </property>
- </bean>
- </beans>
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
<bean id="jotm" class="org.springframework.transaction.jta.JotmFactoryBean"/>
<bean id="txManager" class="org.springframework.transaction.jta.JtaTransactionManager">
<property name="userTransaction" ref="jotm" />
</bean>
<bean id="ds1" class="org.enhydra.jdbc.pool.StandardXAPoolDataSource" destroy-method="shutdown">
<property name="dataSource">
<bean class="org.enhydra.jdbc.standard.StandardXADataSource" destroy-method="shutdown">
<property name="transactionManager" ref="jotm" />
<property name="driverName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:MySQL://localhost:3306/test" />
</bean>
</property>
<property name="user" value="root" />
<property name="password" value="admin" />
</bean>
<bean id="ds2" class="org.enhydra.jdbc.pool.StandardXAPoolDataSource" destroy-method="shutdown">
<property name="dataSource">
<bean class="org.enhydra.jdbc.standard.StandardXADataSource" destroy-method="shutdown">
<property name="transactionManager" ref="jotm" />
<property name="driverName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:MySQL://localhost:3306/test2" />
</bean>
</property>
<property name="user" value="root" />
<property name="password" value="admin" />
</bean>
<bean id="template1" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="ds1" />
</bean>
<bean id="template2" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="ds2" />
</bean>
<bean id="dao1" class="com.xa.dao.UserDao1">
<property name="jdbcTemplate">
<ref bean="template1"></ref>
</property>
</bean>
<bean id="dao2" class="com.xa.dao.UserDao2">
<property name="jdbcTemplate">
<ref bean="template2"></ref>
</property>
</bean>
<bean id="userServiceTarget" class="com.xa.service.UserServiceImpl">
<property name="dao1" ref="dao1"/>
<property name="dao2" ref="dao2"/>
</bean>
<bean id="userTest" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager">
<ref bean="txManager"/>
</property>
<property name="target">
<ref bean="userServiceTarget"/>
</property>
<property name="transactionAttributes">
<props>
<prop key="insert*">PROPAGATION_REQUIRED,-Exception</prop>
</props>
</property>
</bean>
</beans>
上面是一個完整的Spring上下文配置,可以看第一個bean “jotm”,實(shí)際上引用了Spring內(nèi)部所提供的對JOTM支持的工廠類,參考下面的配置代碼段
- <bean id="jotm" class="org.springframework.transaction.jta.JotmFactoryBean"/>
<bean id="jotm" class="org.springframework.transaction.jta.JotmFactoryBean"/>
隨后,配置了JTA事務(wù)管理器,并且在管理器中使用上面所配置的jotm,如下面的代碼
- <bean id="txManager" class="org.springframework.transaction.jta.JtaTransactionManager">
- <property name="userTransaction" ref="jotm" />
- </bean>
<bean id="txManager" class="org.springframework.transaction.jta.JtaTransactionManager">
<property name="userTransaction" ref="jotm" />
</bean>
再接下來就是配置多個數(shù)據(jù)源了,使用jotm提供的org.enhydra.jdbc.pool.StandardXAPoolDataSource類,根據(jù)類名可以明確地看出它是用以配置多個數(shù)據(jù)源的啦,配置的代碼如下
- <bean id="ds1" class="org.enhydra.jdbc.pool.StandardXAPoolDataSource" destroy-method="shutdown">
- <property name="dataSource">
- <bean class="org.enhydra.jdbc.standard.StandardXADataSource" destroy-method="shutdown">
- <property name="transactionManager" ref="jotm" />
- <property name="driverName" value="com.mysql.jdbc.Driver" />
- <property name="url" value="jdbc:MySQL://localhost:3306/test" />
- </bean>
- </property>
- <property name="user" value="root" />
- <property name="password" value="admin" />
- </bean>
-
- <bean id="ds2" class="org.enhydra.jdbc.pool.StandardXAPoolDataSource" destroy-method="shutdown">
- <property name="dataSource">
- <bean class="org.enhydra.jdbc.standard.StandardXADataSource" destroy-method="shutdown">
- <property name="transactionManager" ref="jotm" />
- <property name="driverName" value="com.mysql.jdbc.Driver" />
- <property name="url" value="jdbc:MySQL://localhost:3306/test2" />
- </bean>
- </property>
- <property name="user" value="root" />
- <property name="password" value="admin" />
- </bean>
<bean id="ds1" class="org.enhydra.jdbc.pool.StandardXAPoolDataSource" destroy-method="shutdown">
<property name="dataSource">
<bean class="org.enhydra.jdbc.standard.StandardXADataSource" destroy-method="shutdown">
<property name="transactionManager" ref="jotm" />
<property name="driverName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:MySQL://localhost:3306/test" />
</bean>
</property>
<property name="user" value="root" />
<property name="password" value="admin" />
</bean>
<bean id="ds2" class="org.enhydra.jdbc.pool.StandardXAPoolDataSource" destroy-method="shutdown">
<property name="dataSource">
<bean class="org.enhydra.jdbc.standard.StandardXADataSource" destroy-method="shutdown">
<property name="transactionManager" ref="jotm" />
<property name="driverName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:MySQL://localhost:3306/test2" />
</bean>
</property>
<property name="user" value="root" />
<property name="password" value="admin" />
</bean>
這里配置的兩個數(shù)據(jù)源都連接到本地的mysql,實(shí)際上可以連接到不同的db server和不同類型的數(shù)據(jù)庫,已經(jīng)經(jīng)過測試,這里為了方便,在本地建立了兩個不同的數(shù)據(jù)庫(test,test2)做測試。
隨后的配置基本上和普通的Spring上下文配置相同了,根據(jù)不同的數(shù)據(jù)源配置兩個jdbcTemplate,兩個dao分別引用不同的jdbcTemplate, 將兩個dao注入到UserService中, 最后將service納入事務(wù)管理,并在事務(wù)代理配置中配置回滾規(guī)則,意思為如遇異常,則強(qiáng)制回滾內(nèi)容。配置如下所示
- <property name="transactionAttributes">
- <props>
- <prop key="insert*">PROPAGATION_REQUIRED,-Exception</prop>
- </props>
- </property>
<property name="transactionAttributes">
<props>
<prop key="insert*">PROPAGATION_REQUIRED,-Exception</prop>
</props>
</property>
這樣,一個使用JOTM JTA事務(wù)的簡單應(yīng)用算大致成型了,最后,寫一個JUnit,來測試一下結(jié)果
TestXa.java
- package com.xa;
-
- import org.springframework.context.ApplicationContext;
- import org.springframework.test.AbstractDependencyInjectionSpringContextTests;
-
- import com.xa.service.UserService;
-
- public class TestXa extends AbstractDependencyInjectionSpringContextTests
- {
- protected String[] getConfigLocations() {
- return new String[] { "classpath:ApplicationContext-jotm.xml" };
- }
-
- public void testInsertBothDatabase() {
- ApplicationContext ctx = this.getApplicationContext();
- UserService ut = (UserService)ctx.getBean("userTest");
- try {
- ut.insertBothDatabase("1", null);
- }
- catch (Exception e) {
- e.printStackTrace();
- }
- }
- }
package com.xa;
import org.springframework.context.ApplicationContext;
import org.springframework.test.AbstractDependencyInjectionSpringContextTests;
import com.xa.service.UserService;
public class TestXa extends AbstractDependencyInjectionSpringContextTests
{
protected String[] getConfigLocations() {
return new String[] { "classpath:ApplicationContext-jotm.xml" };
}
public void testInsertBothDatabase() {
ApplicationContext ctx = this.getApplicationContext();
UserService ut = (UserService)ctx.getBean("userTest");
try {
ut.insertBothDatabase("1", null);
}
catch (Exception e) {
e.printStackTrace();
}
}
}
在test中,調(diào)用了UserService的insertBothDatabase方法,有兩個參數(shù),userId和UserName,另外在方法的實(shí)現(xiàn)中調(diào)用了兩個使用不同數(shù)據(jù)源dao,分別向兩個不同的數(shù)據(jù)庫插入輸入,而test2數(shù)據(jù)庫的xa_test表中,name字段是不允許為空的,因此,在插入test2數(shù)據(jù)庫時會失敗.
運(yùn)行這個test,然后察看數(shù)據(jù)庫結(jié)果:),test和test2數(shù)據(jù)庫中都沒有插入成功,看serviceImpl中的代碼可以知道,邏輯上dao1會先于dao2執(zhí)行,但是由于JTA事務(wù),在dao2插入數(shù)據(jù)出現(xiàn)異常時整個事務(wù)被回滾,由于事務(wù)被配置在service層,dao1和dao2都被納入一個事務(wù)進(jìn)行管理,呵呵。修改一下方法的參數(shù),修改為
- ut.insertBothDatabase("1", "name1");
ut.insertBothDatabase("1", "name1");
然后再試試test看數(shù)據(jù)庫結(jié)果,如何?
posted on 2008-12-23 15:44
一葉笑天 閱讀(2747)
評論(1) 編輯 收藏 所屬分類:
開源技術(shù)