spring整合atomikos实现分布式事务的方法示例
程序员文章站
2024-02-23 23:52:23
前言
atomikos 是一个为java平台提供增值服务的并且开源类事务管理器,主要用于处理跨数据库事务,比如某个指令在a库和b库都有写操作,业务上要求a库和b库的写操作...
前言
atomikos 是一个为java平台提供增值服务的并且开源类事务管理器,主要用于处理跨数据库事务,比如某个指令在a库和b库都有写操作,业务上要求a库和b库的写操作要具有原子性,这时候就可以用到atomikos。笔者这里整合了一个spring和atomikos的demo,并且通过案例演示说明atomikos的作用。
准备工作
开发工具:idea
数据库:mysql , oracle
正文
源码地址:
演示原理:通过在两个库的写操作之间人为制造异常来观察数据库是否回滚
演示步骤:1.正常写操作,观察数据库值的变化情况
2.在写操作语句之间制造异常,观察数据库值的变化情况
项目结构
从web.xml中可以知道,容器只加载了appliactioncontext.xml,剩下的配置文件除了database.properties外都是无用文件,所以大家如果要在项目中配置的话,仅需要把appliactioncontext.xml中关于atomikos的部分新增到自己项目中就ok了
appliactioncontext.xml
<?xml version="1.0" encoding="utf-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:xsi="http://www.w3.org/2001/xmlschema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context" xsi:schemalocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd"> <!-- 引入数据源信息的properties属性文件 --> <context:property-placeholder location="classpath:database.properties" /> <!-- xa方式 --> <!-- mysql数据库配置 --> <bean id="mysqldatasource" class="com.atomikos.jdbc.atomikosdatasourcebean" destroy-method="close"> <property name="uniqueresourcename" value="datasource1"/> <property name="xadatasourceclassname" value="com.mysql.jdbc.jdbc2.optional.mysqlxadatasource"/> <property name="xaproperties"> <props> <prop key="url">${mysql.qa.db.url}</prop> <prop key="user">${mysql.qa.db.user}</prop> <prop key="password">${mysql.qa.db.password}</prop> </props> </property> <property name="minpoolsize" value="10" /> <property name="maxpoolsize" value="100" /> <property name="borrowconnectiontimeout" value="30" /> <property name="maintenanceinterval" value="60" /> </bean> <!-- oracle数据库配置 --> <bean id="oracledatasource" class="com.atomikos.jdbc.atomikosdatasourcebean" destroy-method="close"> <property name="uniqueresourcename" value="datasource2"/> <property name="xadatasourceclassname" value="oracle.jdbc.xa.client.oraclexadatasource" /> <property name="xaproperties"> <props> <prop key="url">${oracle.qa.db.url}</prop> <prop key="user">${oracle.qa.db.user}</prop> <prop key="password">${oracle.qa.db.password}</prop> </props> </property> <property name="minpoolsize" value="10" /> <property name="maxpoolsize" value="100" /> <property name="borrowconnectiontimeout" value="30" /> <property name="maintenanceinterval" value="60" /> </bean> <bean id="sqlsessionfactory" class="org.mybatis.spring.sqlsessionfactorybean"> <!--<property name="configlocation" value="classpath:mybatis-config-mysql.xml" />--> <property name="datasource" ref="mysqldatasource" /> <property name="mapperlocations" > <list> <value>classpath*:/dao/*.xml</value> </list> </property> </bean> <bean id="sqlsessionfactoryoracle" class="org.mybatis.spring.sqlsessionfactorybean"> <!--<property name="configlocation" value="classpath:mybatis-config.xml" />--> <property name="datasource" ref="oracledatasource" /> <property name="mapperlocations" > <list> <value>classpath*:/daodev/*.xml</value> </list> </property> </bean> <!-- mybatis为不同的mapper注入sqlsessionfactory --> <bean id="mysqltransactiontestdao" class="org.mybatis.spring.mapper.mapperfactorybean"> <property name="sqlsessionfactory" ref="sqlsessionfactory" /> <property name="mapperinterface" value="com.xy.dao.mysqltransactiontestdao" /> </bean> <bean id="transactiontestdao" class="org.mybatis.spring.mapper.mapperfactorybean"> <property name="sqlsessionfactory" ref="sqlsessionfactoryoracle" /> <property name="mapperinterface" value="com.xy.dao.transactiontestdao" /> </bean> <!-- 分布式事务 --> <bean id="atomikostransactionmanager" class="com.atomikos.icatch.jta.usertransactionmanager" init-method="init" destroy-method="close"> <property name="forceshutdown" value="true"/> </bean> <bean id="atomikosusertransaction" class="com.atomikos.icatch.jta.usertransactionimp"> <property name="transactiontimeout" value="300"/> </bean> <bean id="transactionmanager" class="org.springframework.transaction.jta.jtatransactionmanager"> <property name="transactionmanager" ref="atomikostransactionmanager"/> <property name="usertransaction" ref="atomikosusertransaction"/> </bean> <tx:annotation-driven transaction-manager="transactionmanager"/> <context:annotation-config/> <!--<!– 自动扫描controller包下的所有类,如果@controller注入为bean –>--> <!--<!–事务管理层–>--> <context:component-scan base-package="com.xy" /> <!-- 注册拦截器 --> <!--<mvc:interceptors> <bean class="com.springmybatis.system.interceptor.myinterceptor" /> </mvc:interceptors>--> </beans>
适用junit4进行单元测试
package com.xy.controller; import com.xy.daodev.transactiontestservice; import org.junit.test; import org.springframework.beans.factory.annotation.autowired; import org.springframework.test.context.contextconfiguration; import org.springframework.test.context.junit4.abstractjunit4springcontexttests; @contextconfiguration(locations = {"classpath:applicationcontext.xml"}) public class transactiontestmain extends abstractjunit4springcontexttests { @autowired private transactiontestservice transactiontestservice; /** * 在同一事务有多个数据源 */ @test public void multipledatasource2() { transactiontestservice.updatemultipledatasource("1","1", 100l,"1.6"); } }
业务实现,当前没有异常操作
@service public class transactiontestserviceimpl implements transactiontestservice { @autowired @qualifier("mysqltransactiontestdao") private mysqltransactiontestdao mysqltransactiontestdao; @autowired @qualifier("transactiontestdao") private transactiontestdao transactiontestdao; /** * 在同一事务有多个数据源 */ @override @transactional public void updatemultipledatasource(string deuserid, string inuserid, long money,string str) { // 账户1转出操作 mysqltransactiontestdao.decreasemoney(deuserid, money); //integer.parseint(str); // 账户2转入操作 transactiontestdao.increasemoney(inuserid, money); } }
mysql模拟金额转出,oracle模拟金额转入
<update id="decreasemoney" parametertype="java.util.map"> update fx1 set amount=amount - #{1,jdbctype=bigint} where id=#{0,jdbctype=varchar} </update>
<update id="increasemoney"> update fx1 set amount=amount + #{1,jdbctype=bigint} where id=#{0,jdbctype=varchar} </update>
mysql初始金额
oracle初始金额
执行正常操作
mysql当前金额
oracle当前金额
将被屏蔽的制造异常的代码打开
public void updatemultipledatasource(string deuserid, string inuserid, long money,string str) { // 账户1转出操作 mysqltransactiontestdao.decreasemoney(deuserid, money); integer.parseint("skg"); // 账户2转入操作 transactiontestdao.increasemoney(inuserid, money); }
发现mysql和oracle的当前金额都没有变化,说明事务回滚成功,查看日志
发现控制台打印出了异常信息,并且atomikos调用了rollback()方法,从日志也证实了回滚成功。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
推荐阅读
-
spring整合atomikos实现分布式事务的方法示例
-
Spring Mvc下实现以文件流方式下载文件的方法示例
-
WebSocket整合SSM(Spring,Struts2,Maven)的实现示例
-
spring 整合JDBC和AOP事务的方法
-
Spring Session实现分布式session的简单示例
-
mall整合SpringTask实现定时任务的方法示例
-
spring 整合JDBC和AOP事务的方法
-
Spring中使用atomikos+druid实现经典分布式事务的方法
-
Spring AOP中定义切点的实现方法示例
-
SpringBoot 整合 Atomikos 实现分布式多数据源事务管理器