【分布式事务】使用atomikos+jta解决分布式事务问题
一、前言
分布式事务,这个问题困惑了小编很久,在3个月之前,就间断性的研究分布式事务。从MQ方面,数据库事务方面,jta方面。近期终于成功了,使用JTA解决了分布式事务问题。先写一下心得,后面的二级提交也会在研究。
二、介绍
分布式事务
说到分布式事务,可以理解为,由于分布式而引起的事务不一致的问题。随着项目做大,模块拆分,数据库拆分。一次包含增删改操作数据库涉及到了更新两个不同物理节点的数据库,这样的数据库事务只能保证自己处理的部分的事务,但是整个的事务就不能保证一致性。
网上针对分布式事务常见的例子有:转账
我从农行转账100元到建设银行。首先,农行和建行的数据库是分开的,其次要在农行数据库中-100,在建行数据库+100。分布式事务就是要保障建行+100出错了,使得农行回滚为原来的数目。
JTA
JTA(java Transaction API)是JavaEE 13 个开发规范之一。java 事务API,允许应用程序执行分布式事务处理——在两个或多个网络计算机资源上访问并且更新数据。JDBC驱动程序的JTA支持极大地增强了数据访问能力。事务最简单最直接的目的就是保证数据的有效性,数据的一致性。
atomikos
实现JTA事务管理第三方管理工具 ,一个是JOTM,一个是Atomikos。在其他的博客中看到了JOTM最后更新日期是2010年,然后果断研究是Atomikos。
Atomikos TransactionsEssentials 是一个为Java平台提供增值服务的并且开源类事务管理器,以下是包括在这个开源版本中的一些功能:
<code> 全面崩溃 / 重启恢复 兼容标准的SUN公司JTA API 嵌套事务 为XA和非XA提供内置的JDBC适配器
</code>
三、解决分布式事务
3.1 业务说明
业务
有两个数据库,分别在192.168.22.58和192.168.22.58上,分别有t_allusers表和t_student表,业务是要想两个表中添加一条记录,如果后一条失败了,那么前一条要回滚:

3.2 环境说明
3.2 环境说明SSM框架
Mysql
Maven

3.3 引入依赖
3.3 引入依赖<!--分布式事务相关Atomikos+jta--> <dependency> <groupid>com.atomikos</groupid> <artifactid>transactions-jdbc</artifactid> <version>4.0.6</version> </dependency> <dependency> <groupid>javax.transaction</groupid> <artifactid>jta</artifactid> <version>1.1</version> </dependency>
3.4 配置数据源
3.4 配置数据源在spring配置文件applicationContext-dao.xml配置文件中,添加分布式事务相关的配置:jta事务管理器,不同数据库的数据源配置。
<!-- 分布式事务 -->
<!-- jta事务管理器 -->
<bean class="org.springframework.transaction.jta.JtaTransactionManager" id="jtaTransactionManager">
<property name="transactionManager">
<bean class="com.atomikos.icatch.jta.UserTransactionManager" destroy-method="close" init-method="init">
<property name="forceShutdown" value="true"/>
</bean>
</property>
<property name="userTransaction">
<bean class="com.atomikos.icatch.jta.UserTransactionImp">
<property name="transactionTimeout" value="300"/>
</bean>
</property>
</bean>
<!-- 配置数据源 -->
<bean class="com.atomikos.jdbc.AtomikosDataSourceBean" destroy-method="close" id="jtaDataSource1" init-method="init">
<property name="uniqueResourceName" value="ds1">
<property name="xaDataSourceClassName" value="com.mysql.jdbc.jdbc2.optional.MysqlXADataSource">
<property name="xaProperties">
<props>
<prop key="url">
jdbc:mysql://192.168.22.58:3306/db?useUnicode=true&characterEncoding=UTF-8
</prop>
<prop key="user">root</prop>
<prop key="password">root</prop>
<prop key="pinGlobalTxToPhysicalConnection">true</prop>
</props>
</property>
<property name="minPoolSize" value="10"/>
<property name="maxPoolSize" value="100"/>
<property name="borrowConnectionTimeout" value="30"/>
<property name="testQuery" value="select 1"/>
<property name="maintenanceInterval" value="60"/>
</bean>
<!-- 配置数据源 -->
<bean class="com.atomikos.jdbc.AtomikosDataSourceBean" destroy-method="close" id="jtaDataSource2" init-method="init">
<property name="uniqueResourceName" value="ds2"/>
<property name="xaDataSourceClassName" value="com.mysql.jdbc.jdbc2.optional.MysqlXADataSource"/>
<property name="xaProperties">
<props>
<prop key="url">
jdbc:mysql://192.168.22.59:3306/db?useUnicode=true&characterEncoding=UTF-8
</prop>
<prop key="user">root</prop>
<prop key="password">root</prop>
<prop key="pinGlobalTxToPhysicalConnection">true</prop>
</props>
</property>
<property name="minPoolSize" value="10"/>
<property name="maxPoolSize" value="100"/>
<property name="borrowConnectionTimeout" value="30"/>
<property name="testQuery" value="select 1"/>
<property name="maintenanceInterval" value="60"/>
</bean>
3.5 与mybatis整合
3.5 与mybatis整合项目开发使用ssm框架,所以还要配置spring和mybatis整合:
首先通过逆向工程,生成两个数据库中两个表的mapper和实体,这里小编把两个数据库生成的mapper放置到了连个不同的路径下:

spring和mybatis结合,建立两个sqlsessionfactory ,分别管理两个数据库:
<!-- 让spring管理sqlsessionfactory 使用mybatis和spring整合包中的 -->
<bean class="org.mybatis.spring.SqlSessionFactoryBean" id="sqlSessionFactory">
<!-- 数据库连接池 -->
<property name="dataSource" ref="jtaDataSource1"/>
<!-- 加载mybatis的全局配置文件 -->
<property name="configLocation" value="classpath:mybatis/SqlMapConfig.xml"/>
</bean> <bean class="org.mybatis.spring.SqlSessionFactoryBean" id="sqlSessionFactory2">
<!-- 数据库连接池 -->
<property name="dataSource" ref="jtaDataSource2"/>
<!-- 加载mybatis的全局配置文件 -->
<property name="configLocation" value="classpath:mybatis/SqlMapConfig.xml"/>
</bean> <!--指定mybatis的mapper文件的位置-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.dmsd.studentdao"/>
<property name="sqlSessionFactory" ref="sqlSessionFactory"/>
</bean>
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.dmsd.dao"/>
<property name="sqlSessionFactory" ref="sqlSessionFactory2"/>
</bean>
3.6 使用Spring AOP 添加事务
3.6 使用Spring AOP 添加事务这里需要注意的是:通知的事务管理器是jtaTransactionManager,在前面配置Bean的时候配置的。要使用jta的 事务管理器。
<beans xmlns="https://www.springframework.org/schema/beans" xmlns:aop="https://www.springframework.org/schema/aop" xmlns:context="https://www.springframework.org/schema/context" xmlns:p="https://www.springframework.org/schema/p" xmlns:tx="https://www.springframework.org/schema/tx" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" xsi:schemalocation="https://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans-4.2.xsd
https://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context-4.2.xsd
https://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop-4.2.xsd https://www.springframework.org/schema/tx https://www.springframework.org/schema/tx/spring-tx-4.2.xsd
https://www.springframework.org/schema/util https://www.springframework.org/schema/util/spring-util-4.2.xsd">
<!-- 数据源 -->
<property name="dataSource" ref="dataSource"> <!-- 通知 -->
<tx:advice id="txAdvice" transaction-manager="jtaTransactionManager">
<tx:attributes>
<!-- 传播行为 -->
<tx:method name="save*" propagation="REQUIRED"/>
<tx:method name="insert*" propagation="REQUIRED"/>
<tx:method name="add*" propagation="REQUIRED"/>
<tx:method name="create*" propagation="REQUIRED"/>
<tx:method name="delete*" propagation="REQUIRED"/>
<tx:method name="update*" propagation="REQUIRED"/>
<tx:method name="find*" propagation="SUPPORTS" read-only="true"/>
<tx:method name="select*" propagation="SUPPORTS" read-only="true"/>
<tx:method name="get*" propagation="SUPPORTS" read-only="true"/>
</tx:attributes>
</tx:advice>
<!--自动为切面方法中匹配的方法所在的类生成代理对象-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy> </beans>
3.7 实现service
3.7 实现servicepackage com.dmsd.service; import com.dmsd.api.UserService;
import com.dmsd.dao.TAllusersMapper;
import com.dmsd.pojo.TAllusers;
import com.dmsd.pojo.TStudent;
import com.dmsd.pojo.TUser;
import com.dmsd.studentdao.TStudentMapper;
import com.sun.org.apache.bcel.internal.generic.NEW;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service; import javax.sql.DataSource;
import java.util.List;
import java.util.Map; /**
* Created by Ares on 2017/10/24.
*/
@Service
public class UserServiceImpl implements UserService { @Autowired
TAllusersMapper tAllusersMapper; @Autowired
TStudentMapper tStudentMapper; @Override
public void addStudent2() {
TAllusers tAllusers1 = tAllusersMapper.selectByPrimaryKey(1);
System.out.println(tAllusers1); TStudent tStudent = new TStudent();
tStudent.setAddress("langfang");
tStudent.setName("AresCCCC");
tStudentMapper.insert(tStudent); TAllusers tAllusers2 =new TAllusers();
tAllusers2.setAddress("shagnhai");
tAllusers2.setName("AresDDDD");
tAllusersMapper.insert(tAllusers2); // int a =1/0; }
}
3.8 实现Controller
3.8 实现Controller1 package com.dmsd.controller; import com.dmsd.api.UserService;
import com.dmsd.pojo.TUser;
import com.dmsd.tool.JacksonJsonUntil;
import com.fasterxml.jackson.core.JsonProcessingException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody; /**
* Created by Ares on 2017/10/24.
*/
@Controller
public class UserController { //注入api
@Autowired
private UserService userService; @RequestMapping("/addStudent2")
@ResponseBody
public void addStudent2() {
userService.addStudent2();
} }
3.9 运行
3.9 运行在浏览器中输入https://localhost:8080/addStudent2,查看数据库:
当没有报错的时候,数据都插入进来:


当service中的int a =1/0;代码解开注释的时候,就会报错,这样两个库都插入不进去。
四、小结
四、小结分布式事务,系统分布式后,必然会出现的技术问题。
小编就分布式事务来说,小编使用分布式事务的解决机制后,必然会造成性能的消耗。在项目建立的时候,要避免分布式事务,如果实在避免不了,可以采取下面的几个方案:
同一个web服务器,多个数据库,可以使用Atomikos
跨越多个web服务器的事务,如果远程调用支持事务传播,那么使用JTA就可以;如果不支持事务传播,进尽量转化为一个web服务器的情况。
转载:https://www.2cto.com/kf/201801/714523.html
【分布式事务】使用atomikos+jta解决分布式事务问题的更多相关文章
- Spring3.0+Hibernate+Atomikos集成构建JTA的分布式事务--解决多数据源跨库事务
一.概念 分布式事务分布式事务是指事务的参与者.支持事务的服务器.资源服务器以及事务管理器分别位于不同的分布式系统的不同节点之上.简言之,同时操作多个数据库保持事务的统一,达到跨库事务的效果. JTA ...
- spring3.0+Atomikos 构建jta的分布式事务 -- NO
摘自: http://gongjiayun.iteye.com/blog/1570111 spring3.0+Atomikos 构建jta的分布式事务 spring3.0已经不再支持jtom了,不过我 ...
- spring3.0+Atomikos 构建jta的分布式事务
摘自: http://gongjiayun.iteye.com/blog/1570111 spring3.0+Atomikos 构建jta的分布式事务 spring3.0已经不再支持jtom了,不过我 ...
- SpringMVC+MyBatis+JMS+JTA(分布式事务)
SpringMVC+MyBatis 相信已经是如今企业开发中经常使用技术了. 由于一些需求,我们须要集成JMS(我使用的是ActiveMQ).大家应该都知道.MQ也能够觉得是一个数据源.数据也是数据源 ...
- LCN解决分布式事务原理解析+项目实战(原创精华版)
写在前面: 原创不易,如果觉得不错推荐一下,谢谢! 由于工作需要,公司的微服务项目需解决分布式事务的问题,且由我进行分布式事务框架搭建和整合工作. 那么借此机会好好的将解决分布式事务的内容进行整理一下 ...
- 解决分布式事务基本思想Base和CPA理论、最终一致性|刚性事务、柔性事务
在学习解决分布式事务基本思路之前,大家要熟悉一些基本解决分布式事务概念名词比如:CAP与Base理论.柔性事务与刚性事务.理解最终一致性思想,JTA+XA.两阶段与三阶段提交等. 如何保证强一致性呢? ...
- springboot整合多数据源解决分布式事务
一.前言 springboot整合多数据源解决分布式事务. 1.多数据源采用分包策略 2.全局分布式事务管理:jta-atomikos. ...
- 一文教你迅速解决分布式事务 XA 一致性问题
欢迎大家前往腾讯云技术社区,获取更多腾讯海量技术实践干货哦~ 作者:腾讯云数据库团队 近日,腾讯云发布了分布式数据库解决方案(DCDB),其最明显的特性之一就是提供了高于开源分布式事务XA的性能.大型 ...
- 分布式消息队列RocketMQ--事务消息--解决分布式事务
说到分布式事务,就会谈到那个经典的”账号转账”问题:2个账号,分布处于2个不同的DB,或者说2个不同的子系统里面,A要扣钱,B要加钱,如何保证原子性? 一般的思路都是通过消息中间件来实现“最终一致性” ...
随机推荐
- VS---《在VS2010中 使用C++创建和使用DLL》(003)
VS---<在VS2010中 使用C++创建和使用DLL>(003) 这里实现一下,之前写好的一个工程(定义一个函数f + main函数调用),转成DLL.调用DLL测试.在两个工程里,分 ...
- 01 数据库sql
1, 关于mysql,常去的地方有:https://www.yiibai.com/mysql, http://tool.oschina.net/apidocs/apidoc?api=mysql-5.1 ...
- 牛客第十场 F.Popping Balloons
第一维直接遍历 第二维用线段树维护每个最左端可以得到的贡献 在线段树上每次删除一个点会影响到 X X-R X-2*R 3个值 最多操作1e5次 复杂度 6*n*logn(删了还要加回来 #i ...
- 在java的xml文件配置数据库URL地址时提示The reference to entity "characterEncoding" must end with the ';' delimiter.错误信息
配置数据库的URL<property name="url" value="jdbc:mysql://127.0.0.1:3306/micro_message&quo ...
- solr 分面搜索(转载)
原文地址:http://blog.csdn.net/bingduanlbd/article/details/52199347 分面搜索(Faceting)基于索引词项对搜索结果进行分类,同时返回每个分 ...
- linux基础_用户和组的三个文件
1./etc/passwd文件 用户(user)的配置文件,记录用户的各种信息 每行的含义:用户名:口令:用户标识号:组标识号:注释性描述:主目录:登录shell 2./etc/shadow文件 口令 ...
- Solving Docker permission denied while trying to connect to the Docker daemon socket
The error message tells you that your current user can’t access the docker engine, because you’re la ...
- Codeforces Good Bye 2017 908F F. New Year and Rainbow Roads
题 OvO http://codeforces.com/contest/908/problem/F CF 908F 解 需要注意细节的模拟题. 如果三种颜色都存在,则记每两个相邻的G组成一个段,对每个 ...
- .Net利用cwbx.dll call AS400 program得到数据
calling as400 programs from c# http://forums.asp.net/t/1817332.aspx?calling+as400+programs+from+c+ H ...
- Codeforces 1051 D.Bicolorings(DP)
Codeforces 1051 D.Bicolorings 题意:一个2×n的方格纸,用黑白给格子涂色,要求分出k个连通块,求方案数. 思路:用0,1表示黑白,则第i列可以涂00,01,10,11,( ...