Spring 集成 JOTM 的 JTA 事務管理

Spring 中集成 JOTM 配置 JTA 事務:java

假如業務中要用到多個數據庫,咱們但願在業務方法中,當對某一個數據庫的數據表進行操做的事務失敗並回退(rollback),另外某一個數據庫的數據表的操做事務也要回退,但應用通常的事務管理達不到這樣的事務管理效果,這就須要實現 JTA 事務管理了。
這裏咱們在SPring中集成 Object web 的一個開源JTA實現JOTM (能夠在http://jotm.objectweb.org下載完整版) 來實現JTA事務管理。mysql

一、將必須的類包放入類路徑中:
 jotm.jar, xapool.jar, jotm_jrmp_stubs.jar, jta-spect1_0_1.jar, connector-1_5.jar等等。web

二、編寫JOTM配置文件carol.properties,將其放到類路徑下:spring

Java代碼
  1. #JNDI調用協議   
  2. carol.protocols=jrmp   
  3. #不使用CAROL JNDI封裝器   
  4. carol.start.jndi=false  
  5. #不啓動命名服務器   
  6. carol.start.ns=false  

 
三、在MYSQL中建立兩個數據庫 "jtatesta","jtatestb":sql

Java代碼
  1. CREATE DATABASE IF NOT EXISTS jtatesta;   
  2. USE jtatesta;   
  3.   
  4. DROP TABLE IF EXISTS `user`;   
  5. CREATE TABLE `user` (   
  6.   `user_id` int(10) unsigned NOT NULL auto_increment,   
  7.   `user_name` varchar(45) NOT NULL,   
  8.   `user_password` varchar(45) NOT NULL,   
  9.   PRIMARY KEY  (`user_id`)   
  10. ) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=latin1;   
  11.   
  12. INSERT INTO `user` (`user_id`,`user_name`,`user_password`) VALUES    
  13.  (1,'tufu','tufu');   
  14.   
  15. CREATE DATABASE IF NOT EXISTS jtatestb;   
  16. USE jtatestb;   
  17.   
  18. DROP TABLE IF EXISTS `grade`;   
  19. CREATE TABLE `grade` (   
  20.   `grade_id` int(10) unsigned NOT NULL auto_increment,   
  21.   `user_id` int(10) unsigned NOT NULL,   
  22.   `grade` double NOT NULL,   
  23.   PRIMARY KEY  (`grade_id`)   
  24. ) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=latin1;   
  25.   
  26. INSERT INTO `grade` (`grade_id`,`user_id`,`grade`) VALUES    
  27.  (1,0,100);  

 
四、域對象、數據訪問類和其餘事務管理的同樣,如:數據庫

Java代碼
  1. //Domain對象User.java:   
  2. package com.domain;   
  3. import java.io.Serializable;   
  4. public class User implements Serializable {   
  5.     private int user_id;   
  6.     private String user_name;   
  7.     private String user_password;   
  8. ......//省略set、get方法   
  9. }   
  10.   
  11. //Domain對象Grade.java:   
  12. package com.domain;   
  13. import java.io.Serializable;   
  14. public class Grade implements Serializable{   
  15.     private int grade_id;   
  16.     private User user;   
  17.     private double grade;   
  18. .....//省略set、get方法   
  19. }   
  20.   
  21. 應用Spring JDBC的DAO:(省略DAO接口)   
  22. //UserJdbcDao.java:   
  23. package com.dao.jdbc;   
  24. import org.springframework.jdbc.core.support.JdbcDaoSupport;   
  25. import com.dao.UserDao;   
  26. import com.domain.User;   
  27. public class UserJdbcDao extends JdbcDaoSupport implements UserDao{   
  28.     public void addUser(User user){   
  29.         String SQL = "INSERT INTO user(user_id,user_name,user_password) VALUES(?,?,?)";   
  30.         Object[] params = new Object[]{   
  31.             user.getUser_id(),user.getUser_name(),user.getUser_password()   
  32.         };   
  33.         this.getJdbcTemplate().update(SQL, params);   
  34.     }   
  35. }   
  36. //GradeJdbcDao.java:   
  37. package com.dao.jdbc;   
  38. import com.dao.GradeDao;   
  39. import com.domain.Grade;   
  40. import org.springframework.jdbc.core.support.JdbcDaoSupport;   
  41. public class GradeJdbcDao extends JdbcDaoSupport implements GradeDao{   
  42.     public void addGrade(Grade grade){   
  43.         final String SQL = "INSERT INTO grade(user_id,grade) VALUES(?,?)";   
  44.         Object[] params = new Object[]{   
  45.             grade.getUser().getUser_id(),grade.getGrade()   
  46.         };   
  47.         this.getJdbcTemplate().update(SQL, params);   
  48.     }   
  49. }  

 
五、應用了JTA事務管理的業務類(省略了接口),用@Transactional註解標註,以在配置文件中能夠用<tx:annotation-driven>註解驅動自動進行事務加強:服務器

Java代碼
  1. package com.service.impl;   
  2. import com.dao.GradeDao;   
  3. import com.dao.UserDao;   
  4. import com.domain.*;   
  5. import org.springframework.transaction.annotation.Transactional;   
  6. import com.service.MyService;   
  7. @Transactional  
  8. public class MyServiceImpl implements MyService {   
  9.     private UserDao userDao;   
  10.     private GradeDao gradeDao;   
  11.     public void setUserDao(UserDao userDao){   
  12.         this.userDao = userDao;   
  13.     }   
  14.     public void setGradeDao(GradeDao gradeDao){   
  15.         this.gradeDao = gradeDao;   
  16.     }   
  17.     @Transactional(readOnly=false)   
  18.     public void addGrade(User user,Grade grade){   
  19.         //假如但願兩個添加數據的事務,其中有一個添加失敗時,均回滾,   
  20.         //因爲兩個操做是在兩個不一樣的數據庫上進行的,故要JTA事務來進行管理   
  21.         //不然,將會出現添加一個,回滾一個的情形   
  22.         gradeDao.addGrade(grade);    
  23.         userDao.addUser(user);   
  24.     }   
  25. }  

 
六、spring爲JOTM提供了一個org.springframework.transaction.jta.JotmFactoryBean 支持類,能夠用其方便地建立本地JOTM實例。
具體的配置文件app_jta.xml以下:app

Xml代碼
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <beans xmlns="http://www.springframework.org/schema/beans"  
  3.     xmlns:xsp="http://www.w3.org/2001/XMLSchema-instance"  
  4.     xmlns:aop="http://www.springframework.org/schema/aop"  
  5.     xmlns:tx="http://www.springframework.org/schema/tx"  
  6.     xsp:schemaLocation="http://www.springframework.org/schema/beans   
  7.     http://www.springframework.org/schema/beans/spring-beans-2.0.xsd   
  8.     http://www.springframework.org/schema/aop   
  9.     http://www.springframework.org/schema/aop/spring-aop-2.0.xsd   
  10.     http://www.springframework.org/schema/tx   
  11.     http://www.springframework.org/schema/tx/spring-tx-2.0.xsd">  
  12.    <!--JOTM本地實例-->  
  13.     <bean id="jotm" class="org.springframework.transaction.jta.JotmFactoryBean"/>  
  14.     <!--JTA事務管理器-->  
  15.     <bean id="txManager" class="org.springframework.transaction.jta.JtaTransactionManager">  
  16.         <property name="userTransaction" ref="jotm"/><!--指定userTransaction屬性引用JOTM本地實例-->  
  17.     </bean>  
  18.     <!--XAPool配置,內部包含了一XA數據源,對應了數據庫jtatesta   
  19.     支持JTA事務的數據源,必須封裝成XAPool-->  
  20.     <bean id="jtaTestADS" class="org.enhydra.jdbc.pool.StandardXAPoolDataSource"  
  21.     destroy-method="shutdown">  
  22.         <property name="dataSource"><!--內部XA數據源-->  
  23.             <bean class="org.enhydra.jdbc.standard.StandardXADataSource"  
  24.             destroy-method="shutdown">  
  25.                 <property name="transactionManager" ref="jotm"/>  
  26.                 <property name="driverName" value="com.mysql.jdbc.Driver"/>  
  27.                 <property name="url" value="jdbc:mysql://localhost/jtatesta"/>  
  28.             </bean>  
  29.         </property>  
  30.         <property name="user" value="root"/>  
  31.         <property name="password" value="885123"/>  
  32.     </bean>  
  33.     <!--相似地,對應了數據庫jtatestb的XAPool配置,內部包含了一XA數據源-->  
  34.     <bean id="jtaTestBDS" class="org.enhydra.jdbc.pool.StandardXAPoolDataSource"  
  35.     destroy-method="shutdown">  
  36.         <property name="dataSource"><!--內部XA數據源-->  
  37.             <bean class="org.enhydra.jdbc.standard.StandardXADataSource"  
  38.             destroy-method="shutdown">  
  39.                 <property name="transactionManager" ref="jotm"/>  
  40.                 <property name="driverName" value="com.mysql.jdbc.Driver"/>  
  41.                 <property name="url" value="jdbc:mysql://localhost/jtatestb"/>  
  42.             </bean>  
  43.         </property>  
  44.         <property name="user" value="root"/>  
  45.         <property name="password" value="885123"/>  
  46.     </bean>  
  47.   
  48.     <!--分別配置訪問jtaTestADS、jtaTestBDS數據源的Spring JDBC模板-->  
  49.     <bean id="jtaTestATemplate" class="org.springframework.jdbc.core.JdbcTemplate">  
  50.         <property name="dataSource" ref="jtaTestADS"/>  
  51.     </bean>  
  52.     <bean id="jtaTestBTemplate" class="org.springframework.jdbc.core.JdbcTemplate">  
  53.         <property name="dataSource" ref="jtaTestBDS"/>  
  54.     </bean>  
  55.   
  56.     <!--分別配置基於模板jtaTestADS,jtaTestBDS的DAO-->  
  57.     <bean id="userDao" class="com.dao.jdbc.UserJdbcDao">  
  58.         <property name="jdbcTemplate" ref="jtaTestATemplate"/>  
  59.     </bean>  
  60.     <bean id="gradeDao" class="com.dao.jdbc.GradeJdbcDao">  
  61.         <property name="jdbcTemplate" ref="jtaTestBTemplate"/>  
  62.     </bean>  
  63.   
  64.     <!--跨數據庫的JTA事務的業務類-->  
  65.     <bean id="myService" class="com.service.impl.MyServiceImpl">  
  66.         <property name="userDao" ref="userDao"/>  
  67.         <property name="gradeDao" ref="gradeDao"/>  
  68.     </bean>  
  69.  <!--註解事務驅動-->  
  70.     <tx:annotation-driven transaction-manager="txManager" proxy-target-class="true"/>  
  71.   
  72. </beans>  

 

七、測試main方法:dom

Java代碼
  1. import com.service.MyService;   
  2. import com.service.impl.MyServiceImpl;   
  3. import com.domain.*;   
  4. import org.springframework.context.support.ClassPathXmlApplicationContext;   
  5.   
  6. public class TestMain {   
  7.     public static void main(String args[]){   
  8.         ClassPathXmlApplicationContext ctx =   
  9.                 new ClassPathXmlApplicationContext("beans_jta.xml");   
  10.         MyService ms = (MyServiceImpl)ctx.getBean("myService");   
  11.         User user = new User();   
  12. //特地添加一個重複的主鍵,以使添加user的事務失敗並回退   
  13. //若是此時應用JTA事務失敗,將仍會執行添加grade的事務並提交(前提是先於添加user操做)   
  14. //若是應用JTA事務成功,就會兩個添加事務同時執行或同時回退。   
  15.         user.setUser_id(1);    
  16.         user.setUser_name("tufu");   
  17.         user.setUser_password("tufu");   
  18.         Grade grade = new Grade();   
  19.         grade.setGrade(100);   
  20.         grade.setUser(user);   
  21.   
  22.         ms.addGrade(user,grade);   
  23.     }   
  24. }   
  25.   
  26.    

 注:將log4j.properties中的log4j日誌設置爲DEBUG級別,能夠看到詳細的JTA事務執行狀況:
.......
log4j.rootLogger=DEBUG,R,A1
.......測試

相關文章
相關標籤/搜索