spring+jotm+ibatis+mysql实现JTA分布式事务

1 环境

1.1 软件环境

 spring-framework-2.5.6.SEC01-with-dependencies.zip
 ibatis-2.3.4
 ow2-jotm-dist-2.1.4-bin.tar.gz
 MySQL-5.1
 JDK1.5
 
1.2 创建数据库环境
注意mysql里数据库引擎为InnoDB,只有这样才能支持事务
 1 CREATE DATABASE IF NOT EXISTS testdb_a    DEFAULT CHARACTER SET utf8; 
 2 
 3 USE testdb_a; 
 4 
 5 DROP TABLE IF EXISTS tab_a; 
 6 
 7 CREATE TABLE tab_a ( 
 8     id bigint(20) NOT NULL, 
 9     name varchar(60) DEFAULT NULL, 
10     address varchar(120) DEFAULT NULL, 
11     PRIMARY KEY (id) 
12 ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 
13 
14 
15 CREATE DATABASE IF NOT EXISTS testdb_b    DEFAULT CHARACTER SET utf8; 
16 
17 USE testdb_b; 
18 
19 DROP TABLE IF EXISTS tab_b; 
20 
21 CREATE TABLE tab_b ( 
22     id bigint(20) NOT NULL, 
23     name varchar(60) DEFAULT NULL, 
24     address varchar(120) DEFAULT NULL, 
25     PRIMARY KEY (id) 
26 ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 
View Code

建立项目testJOTM

2.1 建立项目后,准备依赖的类库,结构如下

2.2 主要代码

 1 /**
 2  * 测试JOTM的Service
 3  *
 4  * @author leizhimin 2009-6-25 12:53:55
 5  */
 6 public interface StuJotmService {
 7     /**
 8      * 同时保存TabA、TabB
 9      *
10      * @param a
11      *            TabA对象
12      * @param b
13      *            TabB对象
14      */
15     void saveAB(TabA a, TabB b);
16 
17     /**
18      * 同时更新TabA、TabB
19      *
20      * @param a
21      *            TabA对象
22      * @param b
23      *            TabB对象
24      */
25     void updateAB(TabA a, TabB b);
26 
27     /**
28      * 删除指定id的TabA、TabB记录
29      *
30      * @param id
31      *            指定id
32      */
33     void deleteABif(Long id);
34 }
StuJotmService
 1 public class StuJotmServiceImpl implements StuJotmService {
 2     private TabADAO tabADAO;
 3     private TabBDAO tabBDAO;
 4 
 5     /**
 6      * 同时保存TabA、TabB
 7      *
 8      * @param a
 9      *            TabA对象
10      * @param b
11      *            TabB对象
12      */
13 //    @Transactional(readOnly=false)
14     public void saveAB(TabA a, TabB b) {
15         tabADAO.saveTabA(a);
16         tabBDAO.saveTabB(b);
17     }
18 
19     /**
20      * 同时更新TabA、TabB
21      *
22      * @param a
23      *            TabA对象
24      * @param b
25      *            TabB对象
26      */
27     // @Transactional(readOnly=false)
28     public void updateAB(TabA a, TabB b) {
29         tabADAO.updateTabA(a);
30         tabBDAO.updateTabB(b);
31     }
32 
33     /**
34      * 删除指定id的TabA、TabB记录
35      *
36      * @param id
37      *            指定id
38      */
39     // @Transactional(readOnly=false)
40     public void deleteABif(Long id) {
41         tabADAO.deleteTabAById(id);
42         tabBDAO.deleteTabBById(id);
43     }
44 
45     public void setTabADAO(TabADAO tabADAO) {
46         this.tabADAO = tabADAO;
47     }
48 
49     public void setTabBDAO(TabBDAO tabBDAO) {
50         this.tabBDAO = tabBDAO;
51     }
52 }
StuJotmServiceImpl
  1 <?xml version="1.0" encoding="UTF-8"?>
  2 <!-- 局部单元测试使用,不正式发布,不要删除 -->
  3 <beans xmlns="http://www.springframework.org/schema/beans"
  4     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jee="http://www.springframework.org/schema/jee"
  5     xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
  6     xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
  7                      http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-2.0.xsd
  8                      http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
  9                      http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd">
 10 
 11     <!--指定Spring配置中用到的属性文件 -->
 12     <bean id="propertyConfig"
 13         class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
 14         <property name="locations">
 15             <list>
 16                 <value>classpath:jdbc.properties</value>
 17             </list>
 18         </property>
 19     </bean>
 20     <!-- JOTM实例 -->
 21     <bean id="jotm" class="org.springframework.transaction.jta.JotmFactoryBean" />
 22     <!-- JTA事务管理器 -->
 23     <bean id="myJtaManager"
 24         class="org.springframework.transaction.jta.JtaTransactionManager">
 25         <property name="userTransaction">
 26             <ref local="jotm" />
 27         </property>
 28     </bean>
 29     <!-- 数据源A -->
 30     <bean id="dataSourceA" class="org.enhydra.jdbc.pool.StandardXAPoolDataSource"
 31         destroy-method="shutdown">
 32         <property name="dataSource">
 33             <bean class="org.enhydra.jdbc.standard.StandardXADataSource"
 34                 destroy-method="shutdown">
 35                 <property name="transactionManager" ref="jotm" />
 36                 <property name="driverName" value="${jdbc.driver}" />
 37                 <property name="url" value="${jdbc.url}" />
 38             </bean>
 39         </property>
 40         <property name="user" value="${jdbc.username}" />
 41         <property name="password" value="${jdbc.password}" />
 42     </bean>
 43     <!-- 数据源B -->
 44     <bean id="dataSourceB" class="org.enhydra.jdbc.pool.StandardXAPoolDataSource"
 45         destroy-method="shutdown">
 46         <property name="dataSource">
 47             <bean class="org.enhydra.jdbc.standard.StandardXADataSource"
 48                 destroy-method="shutdown">
 49                 <property name="transactionManager" ref="jotm" />
 50                 <property name="driverName" value="${jdbc2.driver}" />
 51                 <property name="url" value="${jdbc2.url}" />
 52             </bean>
 53         </property>
 54         <property name="user" value="${jdbc2.username}" />
 55         <property name="password" value="${jdbc.password}" />
 56     </bean>
 57     <!-- 事务切面配置 -->
 58     <aop:config>
 59         <aop:pointcut id="serviceOperation" expression="execution(* *..service*..*(..))" />
 60         <aop:advisor pointcut-ref="serviceOperation" advice-ref="txAdvice" />
 61     </aop:config>
 62     <!-- 通知配置 -->
 63     <tx:advice id="txAdvice" transaction-manager="myJtaManager">
 64         <tx:attributes>
 65             <tx:method name="delete*" rollback-for="Exception" />
 66             <tx:method name="save*" rollback-for="Exception" />
 67             <tx:method name="update*" rollback-for="Exception" />
 68             <tx:method name="*" read-only="true" rollback-for="Exception" />
 69         </tx:attributes>
 70     </tx:advice>
 71 
 72     <!--根据dataSourceA和sql-map-config_A.xml创建一个SqlMapClientA -->
 73     <bean id="sqlMapClientA" class="org.springframework.orm.ibatis.SqlMapClientFactoryBean">
 74         <property name="dataSource">
 75             <ref local="dataSourceA" />
 76         </property>
 77         <property name="configLocation">
 78             <value>sql-map-config_A.xml</value>
 79         </property>
 80     </bean>
 81     <!--根据dataSourceB和sql-map-config_B.xml创建一个SqlMapClientB -->
 82     <bean id="sqlMapClientB" class="org.springframework.orm.ibatis.SqlMapClientFactoryBean">
 83         <property name="dataSource">
 84             <ref local="dataSourceB" />
 85         </property>
 86         <property name="configLocation">
 87             <value>sql-map-config_B.xml</value>
 88         </property>
 89     </bean>
 90     <!--根据sqlMapClientA创建一个SqlMapClientTemplate的模版类实例sqlMapClientTemplateA -->
 91     <bean id="sqlMapClientTemplateA" class="org.springframework.orm.ibatis.SqlMapClientTemplate">
 92         <property name="sqlMapClient" ref="sqlMapClientA" />
 93     </bean>
 94     <!--根据sqlMapClientB创建一个SqlMapClientTemplate的模版类实例sqlMapClientTemplateB -->
 95     <bean id="sqlMapClientTemplateB" class="org.springframework.orm.ibatis.SqlMapClientTemplate">
 96         <property name="sqlMapClient" ref="sqlMapClientB" />
 97     </bean>
 98 
 99     <!-- 配置DAO,并注入所使用的sqlMapClientTemplate实例 -->
100     <bean id="tabADAO" class="com.lavasoft.stu.jtom.dao.impl.TabADAOImpl">
101         <property name="sqlMapClientTemplate" ref="sqlMapClientTemplateA" />
102     </bean>
103     <bean id="tabBDAO" class="com.lavasoft.stu.jtom.dao.impl.TabBDAOImpl">
104         <property name="sqlMapClientTemplate" ref="sqlMapClientTemplateB" />
105     </bean>
106 
107     <!-- Service配置,注入DAO -->
108     <bean id="stuJotmService" class="com.lavasoft.stu.jtom.service.StuJotmServiceImpl">
109         <property name="tabADAO" ref="tabADAO" />
110         <property name="tabBDAO" ref="tabBDAO" />
111     </bean>
112 </beans>
applicationContext.xml
 1 jdbc.database=cms_release
 2 jdbc.driver=com.mysql.jdbc.Driver
 3 jdbc.url=jdbc:mysql://192.168.0.1:3306/test?useUnicode=true&characterEncoding=utf8&autoReconnect=true&zeroDateTimeBehavior=convertToNull
 4 jdbc.username=root
 5 jdbc.password=123456
 6 
 7 jdbc2.database=cms_release
 8 jdbc2.driver=com.mysql.jdbc.Driver
 9 jdbc2.url=jdbc:mysql://192.168.0.2:3306/test?useUnicode=true&characterEncoding=utf8&autoReconnect=true&zeroDateTimeBehavior=convertToNull
10 jdbc2.username=root
11 jdbc2.password=123456
jdbc.properties
 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <!DOCTYPE sqlMapConfig
 3                 PUBLIC "-//ibatis.apache.org//DTD SQL Map Config 2.0//EN"
 4                 "http://ibatis.apache.org/dtd/sql-map-config-2.dtd">
 5 
 6 <sqlMapConfig>
 7         <settings cacheModelsEnabled="true" enhancementEnabled="true"
 8                             lazyLoadingEnabled="true" errorTracingEnabled="true"
 9                             useStatementNamespaces="true"/>
10 
11         <sqlMap resource="com/lavasoft/stu/jtom/entity/sqlmap/TabA.xml"/>
12 
13 </sqlMapConfig>
sql-map-config_A.xml
 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <!DOCTYPE sqlMapConfig
 3                 PUBLIC "-//ibatis.apache.org//DTD SQL Map Config 2.0//EN"
 4                 "http://ibatis.apache.org/dtd/sql-map-config-2.dtd">
 5 
 6 <sqlMapConfig>
 7         <settings cacheModelsEnabled="true" enhancementEnabled="true"
 8                             lazyLoadingEnabled="true" errorTracingEnabled="true"
 9                             useStatementNamespaces="true"/>
10 
11         <sqlMap resource="com/lavasoft/stu/jtom/entity/sqlmap/TabB.xml"/>
12 
13 </sqlMapConfig>
sql-map-config_B.xml
 1 public class Test {
 2     private static ApplicationContext ctx = ApplicationContextUtil.getApplicationContext();
 3     private static StuJotmService ser = (StuJotmService) ctx.getBean("stuJotmService");
 4 
 5     public static void test_() {
 6         TabA a = new TabA();
 7         a.setId(2L);
 8         a.setName("aaa4");
 9         a.setAddress("address a4");
10 
11         TabB b = new TabB();
12         b.setId(3L);
13         b.setName("bbb3");
14         b.setAddress("address b5");
15         
16         ser.saveAB(a, b);
17     }
18 
19     public static void main(String[] args) {
20         test_();
21     }
22 }

2.3 测试效果

先运行Test文件,可以看到两个库两个表都正常插入值。

 

再把TabA的setId改为其他任意一个长整型,那么TabB肯定会报主键重复错,因为TabB的setId没改,那么如果事务生效的话,最后应该是两张表都没插入值,如果事务没生效,那么TabA会插入一条新的数据。

 

 2.3 完整结构

 完整代码下载:

原文地址:https://www.cnblogs.com/shamo89/p/7307961.html