Spring 多数据库事务的一致性(JTA 和 非JTA)

  1. 这里的项目是基于 Spring4.X + hibernate4.X架构的。最近的一个项目需要两个数据库,一个Oracle,一个是Sqlserver。业务中有一些需求需要跨库事务的一致,举个例子:合同签订保存到基于Oracle的ERP数据库,紧接着下发到Sqlserver的WMS数据库。
  2. 以前听说过JTA分布式事务,google到两种分布式框架:JOTM,atomikos。貌似JOTM简便点,就它了。
  3. 这种方式需要的jar包,首先在JOTM官网下面所有的jar包文件(文末提供下载),下图中选中的jar文件都是需要导入的

     

    首先配置DataSource和SessionFactory

 

Xml代码 

 收藏代码

  1. <!-- 数据库连接池 -->  
  2.     <bean id="dataSource1" class="org.enhydra.jdbc.pool.StandardXAPoolDataSource">  
  3.          <property name="dataSource">    
  4.             <bean class="org.enhydra.jdbc.standard.StandardXADataSource" destroy-method="shutdown">    
  5.                 <property name="transactionManager" ref="jotm" />    
  6.                 <property name="driverName" value="oracle.jdbc.driver.OracleDriver" />    
  7.                 <property name="url" value="jdbc:oracle:thin:@192.168.1.200:1521:orcl" />    
  8.             </bean>    
  9.         </property>       
  10.         <property name="user" value="${jdbc.username}" />    
  11.         <property name="password" value="${jdbc.password}" />   
  12.     </bean>  
  13.     <bean id="dataSource2" class="org.enhydra.jdbc.pool.StandardXAPoolDataSource"  
  14.         >  
  15.          <property name="dataSource">    
  16.             <bean class="org.enhydra.jdbc.standard.StandardXADataSource" destroy-method="shutdown">    
  17.                 <property name="transactionManager" ref="jotm" />    
  18.                 <property name="driverName" value="com.microsoft.sqlserver.jdbc.SQLServerDriver" />    
  19.                 <property name="url" value="jdbc:sqlserver://192.168.1.200:1433;DatabaseName=middle_db" />    
  20.             </bean>    
  21.         </property>       
  22.         <property name="user" value="${jdbc2.username}" />    
  23.         <property name="password" value="${jdbc2.password}" />    
  24.     </bean>  
  25.     <bean id="sessionFactory1"  
  26.         class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">  
  27.         <property name="dataSource" ref="dataSource1" />  
  28.         <property name="packagesToScan">  
  29.             <list>  
  30.                 <value>com.sy.domain</value>  
  31.             </list>  
  32.         </property>  
  33.         <property name="hibernateProperties">  
  34.             <props>  
  35.                 <prop key="hibernate.dialect">  
  36.                     org.hibernate.dialect.OracleDialect  
  37.                 </prop>  
  38.                 <prop key="hibernate.show_sql">true</prop>  
  39.                 <prop key="hibernate.autoReconnect">true</prop>  
  40.                 <!-- <prop key="hibernate.hbm2ddl.auto">update</prop> -->  
  41.             </props>  
  42.         </property>  
  43.     </bean>  
  44.       
  45.     <bean id="sessionFactory2"  
  46.         class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">  
  47.         <property name="dataSource" ref="dataSource2" />  
  48.         <property name="packagesToScan">  
  49.             <list>  
  50.                 <value>com.sy.domain</value>  
  51.             </list>  
  52.         </property>  
  53.         <property name="hibernateProperties">  
  54.             <props>  
  55.                 <prop key="hibernate.dialect">  
  56.                     org.hibernate.dialect.SQLServerDialect  
  57.                 </prop>  
  58.                 <prop key="hibernate.show_sql">true</prop>  
  59.                 <prop key="hibernate.autoReconnect">true</prop>  
  60.                 <!-- <prop key="hibernate.hbm2ddl.auto">update</prop> -->  
  61.             </props>  
  62.         </property>  
  63.     </bean>  
  64.     <!-- erp.dao -->  
  65.     <bean id="commonDao" class="com.sy.dao.impl.CommonDaoImpl" >  
  66.         <property name="sessionFactory" ref="sessionFactory1"/>  
  67.     </bean>  
  68.     <!-- wms.dao -->  
  69.     <bean id="commonDao2" class="com.sy.dao.impl.CommonDaoImpl" >  
  70.         <property name="sessionFactory" ref="sessionFactory2"/>  
  71.     </bean>  

  因为我们要操作两个数据库,所以配置两个datasource,两个sessionfactory。需要注意的是我们这里是JOTM和xapool实现的分布式事务。JOTM实现了TransactionManager的功能,xapool通过使用非XA数据库驱动实现了XA数据库驱动的效果,具体这个以后再写文章。这里连接池的配置按照上面的文档配置即可。

 

这里DAO层因为两个数据库所以配置了两个。在Service层可以选择一起注入或者单个注入。

 

下面配置事务

Xml代码 

 收藏代码

  1. <bean id="jotm" class="com.sy.utils.JotmFactoryBean"/>    
  2.   <bean id="jtaTransactionManager"  class="org.springframework.transaction.jta.JtaTransactionManager">     
  3.      <property name="userTransaction" ref="jotm" />    
  4.     </bean>   
  5.     <tx:advice id="txAdvice" transaction-manager="jtaTransactionManager">  
  6.         <tx:attributes>  
  7.             <!-- 传播行为 -->  
  8.             <tx:method name="save*" propagation="REQUIRED"  rollback-for="com.sy.exceptions.MyException"/>  
  9.             <tx:method name="insert*" propagation="REQUIRED" rollback-for="com.sy.exceptions.MyException"/>  
  10.             <tx:method name="add*" propagation="REQUIRED" rollback-for="com.sy.exceptions.MyException"/>  
  11.             <tx:method name="create*" propagation="REQUIRED" rollback-for="com.sy.exceptions.MyException"/>  
  12.             <tx:method name="delete*" propagation="REQUIRED" rollback-for="com.sy.exceptions.MyException"/>  
  13.             <tx:method name="update*" propagation="REQUIRED" rollback-for="com.sy.exceptions.MyException"/>  
  14.             <tx:method name="find*" propagation="SUPPORTS" read-only="true" />  
  15.             <tx:method name="select*" propagation="SUPPORTS" read-only="true" />  
  16.             <tx:method name="get*" propagation="SUPPORTS" read-only="true" />  
  17.         </tx:attributes>  
  18.     </tx:advice>  
  19.     <!-- 切面 -->  
  20.     <aop:config expose-proxy="true">  
  21.         <aop:pointcut id="bussinessService" expression="execution(* com.sy.service.*.*(..))" />  
  22.         <aop:advisor pointcut-ref="bussinessService" advice-ref="txAdvice"/>  
  23.     </aop:config>  
  24.      <tx:annotation-driven transaction-manager="jtaTransactionManager"/>    

  com.sy.utils.JotmFactoryBean需要手动实现,因为spring4.x不在提供JtaTransactionManager 的默认实现。

 

 

到这里JTA分布式事务的配置已经完成,下面我们看看Service层,和junit测试

Java代码 

 收藏代码

  1. @Service  
  2. public class CommonServiceImpl implements CommonService{  
  3.       
  4.     /** serialVersionUID*/  
  5.     private static final long serialVersionUID = -5991777455696969065L;  
  6.     @Resource  
  7.     private CommonDao commonDao;  
  8.     @Resource  
  9.     private CommonDao commonDao2;  
  10.         //测试两个数据库的事务  
  11.     @Override  
  12.     public void saveTest() throws MyException {  
  13.         commonDao.update("update Dictionary set name=? where id=? ", new Value().add("货主类型").add(1l).getParams());  
  14.         commonDao2.update("delete Member where id>25");  
  15.                 int i = 1/0; //这里异常,前面配置正确的话事务会回滚  
  16.     }  
  17.   
  18. }  

 

   因为这是一个公共的Service层,需要操作两个数据库,所以两个DAO一起注入。下面是Junit测试代码

Java代码 

 收藏代码

  1. @RunWith(SpringJUnit4ClassRunner.class)  
  2. @ContextConfiguration(locations = {"classpath:spring/applicationContext-*.xml"})  
  3. public class TestSupport extends AbstractJUnit4SpringContextTests {  
  4.   
  5.         @Autowired  
  6.     private CommonService commonService;  
  7.     @Test  
  8.     public void save() throws MyException{  
  9.         commonService.saveTest();  
  10.     }  
  11.     public CommonService getCommonService() {  
  12.         return commonService;  
  13.     }  
  14.     public void setCommonService(CommonService commonService) {  
  15.         this.commonService = commonService;  
  16.     }  
  17.   
  18.   
  19. }  

  运行结果如我们所料,事务回滚,OK!

 

下面是直接配置的方式,这种方式是一个老同事那边看到的。当时惊呼不用jta也能实现跨库事务啊。跟普通的单数据库项目配置一样,只是DataSource,SessionFactory,transactionmanager等都是两个。下面是配置

Xml代码 

 收藏代码

  1. <!-- 数据库连接池 -->  
  2.     <bean id="dataSource1" class="com.alibaba.druid.pool.DruidDataSource"  
  3.         destroy-method="close">  
  4.         <property name="url" value="${jdbc.url}" />  
  5.         <property name="username" value="${jdbc.username}" />  
  6.         <property name="password" value="${jdbc.password}" />  
  7.         <property name="driverClassName" value="${jdbc.driver}" />  
  8.         <property name="maxActive" value="${jdbc.maxActive}" />  
  9.         <property name="minIdle" value="${jdbc.minIdle}" />  
  10.     </bean>  
  11.     <bean id="dataSource2" class="com.alibaba.druid.pool.DruidDataSource"  
  12.         destroy-method="close">  
  13.         <property name="url" value="${jdbc2.url}" />  
  14.         <property name="username" value="${jdbc2.username}" />  
  15.         <property name="password" value="${jdbc2.password}" />  
  16.         <property name="driverClassName" value="${jdbc2.driver}" />  
  17.         <property name="maxActive" value="${jdbc2.maxActive}" />  
  18.         <property name="minIdle" value="${jdbc2.minIdle}" />  
  19.     </bean>  
  20.     <bean id="sessionFactory1"  
  21.         class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">  
  22.         <property name="dataSource" ref="dataSource1" />  
  23.         <property name="packagesToScan">  
  24.             <list>  
  25.                 <value>com.sy.domain</value>  
  26.             </list>  
  27.         </property>  
  28.         <property name="hibernateProperties">  
  29.             <props>  
  30.                 <prop key="hibernate.dialect">  
  31.                     org.hibernate.dialect.OracleDialect  
  32.                 </prop>  
  33.                 <prop key="hibernate.show_sql">true</prop>  
  34.                 <prop key="hibernate.autoReconnect">true</prop>  
  35.                 <!-- <prop key="hibernate.hbm2ddl.auto">update</prop> -->  
  36.             </props>  
  37.         </property>  
  38.     </bean>  
  39.       
  40.     <bean id="sessionFactory2"  
  41.         class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">  
  42.         <property name="dataSource" ref="dataSource2" />  
  43.         <property name="packagesToScan">  
  44.             <list>  
  45.                 <value>com.sy.domain</value>  
  46.             </list>  
  47.         </property>  
  48.         <property name="hibernateProperties">  
  49.             <props>  
  50.                 <prop key="hibernate.dialect">  
  51.                     org.hibernate.dialect.SQLServerDialect  
  52.                 </prop>  
  53.                 <prop key="hibernate.show_sql">true</prop>  
  54.                 <prop key="hibernate.autoReconnect">true</prop>  
  55.                 <!-- <prop key="hibernate.hbm2ddl.auto">update</prop> -->  
  56.             </props>  
  57.         </property>  
  58.     </bean>  
  59.       
  60.     <bean id="commonDao" class="com.sy.dao.impl.CommonDaoImpl" >  
  61.         <property name="sessionFactory" ref="sessionFactory1"/>  
  62.     </bean>  
  63.       
  64.     <bean id="commonDao2" class="com.sy.dao.impl.CommonDaoImpl" >  
  65.         <property name="sessionFactory" ref="sessionFactory2"/>  
  66.     </bean>  
  67.      <bean id="transactionManager1" class="org.springframework.orm.hibernate4.HibernateTransactionManager">  
  68.         <property name="sessionFactory" ref="sessionFactory1" />  
  69.     </bean>  
  70.       
  71.     <bean id="transactionManager2" class="org.springframework.orm.hibernate4.HibernateTransactionManager">  
  72.         <property name="sessionFactory" ref="sessionFactory2" />  
  73.     </bean>  
  74.       
  75.     <tx:advice id="txAdvice1" transaction-manager="transactionManager1">  
  76.         <tx:attributes>  
  77.             <!-- 传播行为 -->  
  78.             <tx:method name="save*" propagation="REQUIRED"  rollback-for="com.sy.exceptions.MyException"/>  
  79.             <tx:method name="insert*" propagation="REQUIRED" rollback-for="com.sy.exceptions.MyException"/>  
  80.             <tx:method name="add*" propagation="REQUIRED" rollback-for="com.sy.exceptions.MyException"/>  
  81.             <tx:method name="create*" propagation="REQUIRED" rollback-for="com.sy.exceptions.MyException"/>  
  82.             <tx:method name="delete*" propagation="REQUIRED" rollback-for="com.sy.exceptions.MyException"/>  
  83.             <tx:method name="update*" propagation="REQUIRED" rollback-for="com.sy.exceptions.MyException"/>  
  84.             <tx:method name="find*" propagation="SUPPORTS" read-only="true" />  
  85.             <tx:method name="select*" propagation="SUPPORTS" read-only="true" />  
  86.             <tx:method name="get*" propagation="SUPPORTS" read-only="true" />  
  87.         </tx:attributes>  
  88.     </tx:advice>  
  89.       
  90.     <tx:advice id="txAdvice2" transaction-manager="transactionManager2">  
  91.         <tx:attributes>  
  92.             <!-- 传播行为 -->  
  93.             <tx:method name="save*" propagation="REQUIRED"  rollback-for="com.sy.exceptions.MyException"/>  
  94.             <tx:method name="insert*" propagation="REQUIRED" rollback-for="com.sy.exceptions.MyException"/>  
  95.             <tx:method name="add*" propagation="REQUIRED" rollback-for="com.sy.exceptions.MyException"/>  
  96.             <tx:method name="create*" propagation="REQUIRED" rollback-for="com.sy.exceptions.MyException"/>  
  97.             <tx:method name="delete*" propagation="REQUIRED" rollback-for="com.sy.exceptions.MyException"/>  
  98.             <tx:method name="update*" propagation="REQUIRED" rollback-for="com.sy.exceptions.MyException"/>  
  99.             <tx:method name="find*" propagation="SUPPORTS" read-only="true" />  
  100.             <tx:method name="select*" propagation="SUPPORTS" read-only="true" />  
  101.             <tx:method name="get*" propagation="SUPPORTS" read-only="true" />  
  102.         </tx:attributes>  
  103.     </tx:advice>  
  104.       
  105.     <!-- 切面 -->  
  106.     <aop:config expose-proxy="true">  
  107.         <aop:pointcut id="bussinessService1" expression="execution(* com.sy.service.*.*(..))" />  
  108.         <aop:advisor pointcut-ref="bussinessService1" advice-ref="txAdvice1"/>  
  109.     </aop:config>  
  110.       
  111.     <aop:config expose-proxy="true">  
  112.         <aop:pointcut id="bussinessService2" expression="execution(* com.sy.service.*.*(..))" />  
  113.         <aop:advisor pointcut-ref="bussinessService2" advice-ref="txAdvice2"/>  
  114.     </aop:config>  

  这里配置和普通单库配置基本一样,连接池也是自由选择。但是都是两个配置,spring4对多个事务配置也是支持的。测试代码和上面JTA配置的一样,不再给出。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值