概念

XA是由X/Open组织提出的分布式事务的规范。 XA规范主要定义了(全局)事务管理器(TM)和(局 部)资源管理器(RM)之间的接口。主流的关系型 数据库产品都是实现了XA接口的。
 XA接口是双向的系统接口,在事务管理器 (TM)以及一个或多个资源管理器(RM)之 间形成通信桥梁。
 XA之所以需要引入事务管理器是因为,在分布 式系统中,从理论上讲两台机器理论上无法达 到一致的状态,需要引入一个单点进行协调。
 由全局事务管理器管理和协调的事务,可以跨 越多个资源(如数据库或JMS队列)和进程。 全局事务管理器一般使用 XA 二阶段提交协议 与数据库进行交互。

资源管理器(resource manager):用来管理系统资源,是通向事务资源的途径。数据库就是一种资源管理器。资源管理还应该具有管理事务提交或回滚的能力。
事务管理器(transaction manager):事务管理器是分布式事务的核心管理者。事务管理器与每个资源管理器(resource manager)进行通信,协调并完成事务的处理。事务的各个分支由唯一命名进行标识
Xid 接口 Xid, Xid 接口是 X/Open 事务标识符 XID 结构的 Java 映射。此接口指定三个访问器方法,以检索全局事务格式 ID、全局事务 ID 和分支限定符。Xid 接口供事务管理器和资源管理器使用。此接口对应用程序不可见。

XA 不能自动提交。

分段提交

XA需要两阶段提交: prepare 和 commit. 
第一阶段为 准备(prepare)阶段。即所有的参与者准备执行事务并锁住需要的资源。参与者ready时,向transaction manager报告已准备就绪。

第二阶段为提交阶段(commit)。当transaction manager确认所有参与者都ready后,向所有参与者发送commit命令。

假设有两个Connection, con1, con2, 大体的过程如下 .

con1 = XAResouce1.getConnection...
con2 = XAResouce2.getConnection...   con1 do some thing.
con2 do some thing.
after they finish.     pre1 = XAResouce1.prepare();
pre2 = XAResouce2.prepare();     if( both pre1 and pre2 are OK){
XAResouce1 and 2 commit
}else {
XAResouce1 and 2 rollback
}    

事务协调/管理者

因为XA 事务是基于两阶段提交协议的,所以需要有一个事务协调者(transaction manager)来保证所有的事务参与者都完成了准备工作(第一阶段)。如果事务协调者(transaction manager)收到所有参与者都准备好的消息,就会通知所有的事务都可以提交了(第二阶段)。MySQL 在这个XA事务中扮演的是参与者的角色,而不是事务协调者(transaction manager)。

测试用例

import com.alibaba.druid.pool.xa.DruidXADataSource;
import com.mysql.jdbc.jdbc2.optional.MysqlXid;import javax.sql.XAConnection;
import javax.transaction.xa.XAException;
import javax.transaction.xa.XAResource;
import javax.transaction.xa.Xid;
import java.io.IOException;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;class DistributeTransaction {private Properties props;private String propertyfile = "jdbc.properties";private String sql_1 = "delete from test3 where pk_t=3;";private String sql_2 = "INSERT INTO test(name) VALUES('tyz');";DistributeTransaction() {Connection connection_1 = null;Connection connection_2 = null;DruidXADataSource xaDataSource_1 = null;DruidXADataSource xaDataSource_2 = null;Xid xid_1 = null;Xid xid_2 = null;XAConnection xaConnection_1 = null;XAConnection xaConnection_2 = null;XAResource xaResource_1 = null;XAResource xaResource_2 = null;try {props = new Properties();props.load(getClass().getResourceAsStream(propertyfile));} catch (IOException io) {System.err.println("Error while accessing the properties file (" + propertyfile + "). Abort.");System.exit(1);}DruidXADataSource[] xaDataSources = initXADataSource();xaDataSource_1 = xaDataSources[0];xaDataSource_2 = xaDataSources[1];XAConnection[] xaConnections = initXAConnection(xaDataSource_1, xaDataSource_2);xaConnection_1 = xaConnections[0];xaConnection_2 = xaConnections[1];xaResource_1 = initXAResource(xaConnection_1);xaResource_2 = initXAResource(xaConnection_2);connection_1 = getDatabaseConnection(xaConnection_1);connection_2 = getDatabaseConnection(xaConnection_2);// create a separate branch for a common transactionXid[] xids = createXID();xid_1 = xids[0];xid_2 = xids[1];try {execBranch(connection_1, xaResource_1, xid_1, sql_1);execBranch(connection_2, xaResource_2, xid_2, sql_2);if (prepareCommit(xaResource_1, xid_1) == XAResource.XA_OK &&prepareCommit(xaResource_2, xid_2) == XAResource.XA_OK) {commitBranch(xaResource_1, xid_1);commitBranch(xaResource_2, xid_2);} else {throw new RuntimeException();}} catch (Exception e) {rollbackBranch(xaResource_1, xid_1);rollbackBranch(xaResource_2, xid_2);}}DruidXADataSource[] initXADataSource() {System.out.print("Create a XADataSource_1 data source: ");DruidXADataSource xaDataSource_1 = new DruidXADataSource();xaDataSource_1.setDbType(props.getProperty("db1.dbtype"));xaDataSource_1.setUrl(props.getProperty("db1.url"));xaDataSource_1.setUsername(props.getProperty("db1.username"));xaDataSource_1.setPassword(props.getProperty("db1.password"));System.out.println("Okay.");System.out.print("Create a XADataSource_2 data source: ");DruidXADataSource xaDataSource_2 = new DruidXADataSource();xaDataSource_2.setDbType(props.getProperty("db2.dbtype"));xaDataSource_2.setUrl(props.getProperty("db2.url"));xaDataSource_2.setUsername(props.getProperty("db2.username"));xaDataSource_2.setPassword(props.getProperty("db2.password"));System.out.println("Okay.");return new DruidXADataSource[]{xaDataSource_1, xaDataSource_2};}XAConnection[] initXAConnection(DruidXADataSource xaDataSource_1, DruidXADataSource xaDataSource_2) {XAConnection xaconn_1 = null;XAConnection xaconn_2 = null;try {System.out.print("Set up DB_1 XA connection: ");xaconn_1 = xaDataSource_1.getXAConnection();System.out.println("Okay.");System.out.print("Set up DB_2 XA connection: ");xaconn_2 = xaDataSource_2.getXAConnection();System.out.println("Okay.");} catch (SQLException e) {sqlerr(e);}return new XAConnection[]{xaconn_1, xaconn_2};}XAResource initXAResource(XAConnection xacon) {XAResource xares = null;try {System.out.print("Setting up a XA resource: ");xares = xacon.getXAResource();System.out.println("Okay.");} catch (SQLException e) {sqlerr(e);}return xares;}Connection getDatabaseConnection(XAConnection xacon) {Connection con = null;try {System.out.print("Establish database connection: ");con = xacon.getConnection();con.setAutoCommit(false);System.out.println("Okay.");} catch (SQLException e) {sqlerr(e);}return con;}Xid[] createXID() {Xid xid_1 = null;byte[] gid_1 = new byte[1];byte[] bid_1 = new byte[1];gid_1[0] = (Byte.decode(props.getProperty("xid.global"))).byteValue();bid_1[0] = (Byte.decode(props.getProperty("xid.branch.db_1"))).byteValue();System.out.print("Creating an XID (" + Byte.toString(gid_1[0]) + ", " + Byte.toString(bid_1[0]) + ") for DB_1: ");xid_1 = new MysqlXid(gid_1, bid_1, 0);System.out.println("Okay.");Xid xid_2 = null;byte[] gid_2 = new byte[1];byte[] bid_2 = new byte[1];gid_2[0] = (Byte.decode(props.getProperty("xid.global"))).byteValue();bid_2[0] = (Byte.decode(props.getProperty("xid.branch.db_2"))).byteValue();System.out.print("Creating an XID (" + Byte.toString(gid_2[0]) + ", " + Byte.toString(bid_2[0]) + ") for DB_2: ");xid_2 = new MysqlXid(gid_2, bid_2, 0);System.out.println("Okay.");return new Xid[]{xid_1, xid_2};}void execBranch(Connection con, XAResource xares, Xid xid, String sql) {try {xares.start(xid, XAResource.TMNOFLAGS);Statement stmt = con.createStatement();stmt.executeUpdate(sql);xares.end(xid, XAResource.TMSUCCESS);} catch (XAException e) {System.err.println("XA exception caught:");System.err.println("Cause  : " + e.getCause());System.err.println("Message: " + e.getMessage());e.printStackTrace();throw new RuntimeException(e);} catch (SQLException e) {sqlerr(e);throw new RuntimeException(e);}}int prepareCommit(XAResource xares, Xid xid) {int rc = 0;System.out.print("Prepare XA branch (" +Byte.toString((xid.getGlobalTransactionId())[0]) + ", " +Byte.toString((xid.getBranchQualifier())[0]) + "): ");try {xares.prepare(xid);} catch (XAException e) {xaerr(e);throw new RuntimeException(e);}System.out.println("Okay.");return rc;}void commitBranch(XAResource xares, Xid xid) {System.out.print("Commit XA branch (" +Byte.toString((xid.getGlobalTransactionId())[0]) + ", " +Byte.toString((xid.getBranchQualifier())[0]) + "): ");try {// second parameter is 'false' since we have a two phase commitxares.commit(xid, false);} catch (XAException e) {xaerr(e);throw new RuntimeException(e);}System.out.println("Okay.");}void rollbackBranch(XAResource xares, Xid xid) {System.out.print("Rollback XA branch (" +Byte.toString((xid.getGlobalTransactionId())[0]) + ", " +Byte.toString((xid.getBranchQualifier())[0]) + "): ");try {xares.rollback(xid);} catch (XAException e) {xaerr(e);throw new RuntimeException(e);}System.out.println("Okay.");}void sqlerr(SQLException exception) {System.err.println("FAILED.");while (exception != null) {System.err.println("==> SQL Exception caught");System.err.println("--> SQLCODE : " + exception.getErrorCode());System.err.println("--> SQLSTATE: " + exception.getSQLState());System.err.println("--> Message : " + exception.getMessage());exception = exception.getNextException();}}void xaerr(XAException exception) {System.err.println("FAILED.");System.err.println("==> XA Exception caught");System.err.println("--> Cause  : " + exception.getCause());System.err.println("--> Message: " + exception.getMessage());exception.printStackTrace();}public static void main (String args[]) {new DistributeTransaction();}}

XA性能局限性

效率低下,准备阶段的成本持久,全局事务状态的成本持久,性能与本地事务相差10倍左右;
提交前,出现故障难以恢复和隔离问题。

转载于:https://www.cnblogs.com/wuzhiwei549/p/9113496.html

XA 分布式事务原理相关推荐

  1. 《深入理解分布式事务》第七章 XA 强一致性分布式事务原理

    <深入理解分布式事务>第七章 XA 强一致性分布式事务原理 文章目录 <深入理解分布式事务>第七章 XA 强一致性分布式事务原理 一.X/Open DTP 模型与 XA 规范 ...

  2. 分布式事务:分布式事务原理概述

    1.什么是分布式事务 分布式事务就是指事务的资源分别位于不同的分布式系统的不同节点之上的事务: 2.分布式事务产生的原因 2.1.数据库分库分表 在单库单表场景下,当业务数据量达到单库单表的极限时,就 ...

  3. 一文彻底说明分布式事务原理

    一文彻底说明分布式事务原理 文章目录 一文彻底说明分布式事务原理 前言 1. 单数据源事务 & 多数据源事务 2. 常见分布式事务解决方案 2.1. 分布式事务模型 2.2. 二将军问题和幂等 ...

  4. JAVA分布式事务原理及应用(转)

    JAVA分布式事务原理及应用(转) 引言 JTA(Java Transaction API)允许应用程序执行分布式事务处理--在两个或多个网络计算机资源上访问并且更新数据.JDBC驱动程序的JTA支持 ...

  5. 分布式事务解决方案分布式事务原理

    分布式事务解决方案&分布式事务原理 0. 前言 1. 单数据源事务 & 多数据源事务 2. 常见分布式事务解决方案 2.0.什么是分布式事务 2.1. 分布式事务模型 2.2. 二将军 ...

  6. 分布式事务:RocketMQ实现分布式事务原理

    之前讲过有关分布式事务2PC.3PC.TCC的理论知识,博客地址: 1.分布式事务(1)---2PC和3PC原理 2.分布式事务(2)---TCC原理 这篇讲有关RocketMQ实现分布式事务的理论知 ...

  7. 《深入理解分布式事务》第十章 最大努力通知型分布式事务原理

    <深入理解分布式事务>第十章 最大努力通知型分布式事务原理 文章目录 <深入理解分布式事务>第十章 最大努力通知型分布式事务原理 一.适用场景 二.方案特点 三.基本原理 四. ...

  8. 《深入理解分布式事务》第九章 可靠消息最终一致性分布式事务原理

    <深入理解分布式事务>第九章 可靠消息最终一致性分布式事务原理 文章目录 <深入理解分布式事务>第九章 可靠消息最终一致性分布式事务原理 一.基本原理 二.本地消息表 1.实现 ...

  9. 《深入理解分布式事务》第八章 TCC 分布式事务原理

    <深入理解分布式事务>第八章 TCC 分布式事务原理 文章目录 <深入理解分布式事务>第八章 TCC 分布式事务原理 一.TCC 核心思想 二.TCC 实现原理 1.TCC 核 ...

最新文章

  1. Opencv java模板匹配-角点检测(11)
  2. error40无法打开到sql_SQL入门学习,初步认识ADO
  3. 是知当代之士、驰骛之曹,书读纵横,则思诸侯之变
  4. 道路检测 | SNE-RoadSeg论文阅读
  5. 笔记-项目人力资源管理
  6. PowerDesigner 企业架构模型 ( EAM ) 说明
  7. HDMI光端机基本知识及相关品牌介绍
  8. Java包数据消息头消息尾_读Socket流时产生阻塞的解决方案(粘包拆包问题)
  9. STM32输出比较模式和PWM模式 比较
  10. Intelli IDEA快捷键(配合IdeaVim)
  11. C语言:运行中获取宏名字的技巧
  12. 新版Dede采集不要在用没更新的Dede插件
  13. 直接打印RAW文件到打印机
  14. 017~022 函数 课后练习题
  15. 任务调度+资源调度整合(学习笔记)
  16. 客户标签不能只是个“标签”
  17. sox处理mp3_SoX — 音频处理工具里的瑞士军刀
  18. P2437 蜜蜂路线
  19. ubuntu18.04中基于Docker搭建tensorflow-gpu开发环境
  20. STM 32简单编程实例

热门文章

  1. 《Crossy Road》效仿《Angry Birds》进行周边商品销售
  2. 腾讯云服务器到期多久会清除,腾讯云服务器过期多少天会被回收?
  3. Android github上开源项目、酷炫的交互动画和视觉效果地址集合
  4. 【数据集】数据集BraTS 2015整理
  5. 关于 PHP 中 echo 和 print 和 '.' 运算符混合的运算分析
  6. 深入浅出CChart 每日一课——快乐高四第五十二课 旧梦重温,天上人间之炫彩界面库
  7. 一文读懂智能对话系统,当前研究综述和未来趋势
  8. vscode 的终端不识别npm 命令
  9. LINUX_常用命令讲解
  10. 传智健康——七牛云技术用于图片存储