JTA(Java Transaction API)同意应用程序运行分布式事务处理--在两个或多个网络计算机资源上訪问而且更新数据。JDBC驱动程序的JTA支持极大地增强了数据訪问能力。 



  本文的目的是要提供一个关于的Java事务处理API(JTA)的高级的概述,以及与分布式事务相关的内容。

一个事务处理定义了一个工作逻辑单元,要么彻底成功要么不产生不论什么结果。 一个分布式事务处理仅仅是一个在两个或很多其它网络资源上訪问和更新数据的事务处理,因此它在那些资源之间必定是等价的。在本文中。我们主要关心的是怎样处理关系数据库系统。

  我们要讨论的分布式事务处理(DTP)模型中包括的组件是: 



    应用程序 



    应用程序server 



    事务管理程序 



    资源适配器 



    资源管理程序 



  在以后的内容中。我们将描写叙述这些组件以及它们与JTA和数据库訪问的关系。 



  訪问数据库 



  最好把分布式事务处理中包括的组件看作是独立的过程,而不是考虑它们在一个特定的电脑中的位置。

这些组件中的一些能够保存在单机中,或者也可在好几台机器之间分布。 以下样例中的图表能够显示在一台特定的电脑上的组件。可是这些操作之间的关系是必须首要考虑的。 



  最简单的样例:用于本地数据库事务处理的应用程序 



  关系数据库訪问的最简单的形式只包含应用程序、资源管理程序和资源适配器。应用程序只只是是发送请求到数据库而且从数据库中获取数据的终于用户訪问点 



  我们讨论的资源管理程序是一个关系数据库管理系统(RDBMS),比方Oracle或者SQL Server。

全部的实际数据库管理都是由这个组件处理的。 



  资源适配器是外部空间之间的通信管道组件,或者是请求翻译器,在本例中,是应用程序和资源管理程序。在我们的讨论中,这是一个JDBC驱动程序。

  以下的描写叙述是资源管理程序本地事务处理的一个描写叙述。也就是说,一个事务处理被被限制在一个特定的企业数据库。

  应用程序发送一个用于JDBC驱动程序数据的请求,然后翻译这个请求并把它通过网络发送到数据库中。 数据库把数据发送回驱动程序,然后把翻译的结果发送回应用程序。例如以下图所看到的:

这个样例说明了在一个简化的系统中的主要的信息流;然而,今天的企业使用的应用程序server都加入了其它的组件到这个过程处理中。 







  应用程序server 



  应用程序server是事务处理操作的还有一个组件。应用程序server处理大部分的应用程序操作而且获得终于用户应用程序的一些负载。

基于前面的样例,我们能够看出应用程序server在事务处理上加入了还有一个操作层: 



watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvc3p3YW5nZGY=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">

   



到眼下为止,我们的样例说明了单个的本地事务处理,而且描写叙述了分布式事务处理模型的五个组件中的四个。

第五个组件,事务管理程序仅仅有当事务将要被分配的时候才会開始被考虑。 



  分布式事务处理和事务管理程序 



  像我们前面所提到的,一个分布式事务处理是一个在两个或很多其它网络资源上訪问和更新数据的事务处理。

  这些资源能够由好几个位于一个单独server上的不同的关系型数据库管理系统组成,比方说Oracle、SQL Server和Sybase。它们也能够包括存在于若干不同的server上的同一种数据库的若干个实例。在不论什么情况下。一个分布式事务处理包括各种的资源管理程序之间的协同作用。这个协同作用是事务管理函数。

  事务管理程序负责作出要么提交(commit)要么退回(rollback)不论什么分布式事务处理的决定。一个提交决定应该导致一个成功的事务处理。而退回操作则是保持数据库中的数据不变。 JTA指定一个分布式事务处理中的事务管理程序和还有一个组件之间的标准Java接口:应用程序。应用程序server和资源管理程序。
这个关系被显示在以下的图表中:

  在事务管理程序周围的数字框框对应于JTA的三个接口部分: 



  1—UserTransaction—javax.transaction.UserTransaction接口提供可以编程地控制事务处理范围的应用程序。 javax.transaction.UserTransaction方法开启一个全局事务而且使用调用线程与事务处理关联。 



  2—Transaction Manager—javax.transaction.TransactionManager接口同意应用程序server来控制代表正在管理的应用程序的事务范围。

  3—XAResource—javax.transaction.xa.XAResource接口是一个基于X/Open CAE Specification的行业标准XA接口的Java映射。

  注意,一个限制性环节是通过JDBC驱动程序的XAResource接口的支持。

JDBC驱动程序必须支持两个正常的JDBC交互作用:应用程序和/或应用程序server,并且以及JTA的XAResource部分。 



  编写应用程序水平代码的开发人员不会关心分布式事务处理管理的细节。 这是分布式事务处理基本结构的工作—应用程序server、事务管理程序和JDBC驱动程序。应用程序代码中唯一的须要注意的就是当连接处于一个分布式事务范围内的时候,不应该调用一个会影响事务边界的方法。

特别的是,一个应用程序不应该调用Connection方法commit、rollback和setAutoCommit(true),由于它们将破坏分布式事务的基本结构管理。 



  分布式事务处理 



  事务管理程序是分布式事务基本结构的基本组件;然而JDBC驱动程序和应用程序server组件应该具备以下的特征: 



  驱动程序应该实现JDBC 2.0应用程序接口。包含Optional Package接口XADataSource和XAConnection以及JTA接口XAResource。 



  应用程序server应该提供一个DataSource类。用来实现与分布式事务基本结的交互以及一个连接池模块(用于改善性能)。 



  分布式事务处理的第一步就是应用程序要发送一个事务请求到事务管理程序。尽管最后的commit/rollback决定把事务作为一个简单的逻辑单元来对待,可是仍然可能会包括很多事务分支。一个事务分支与一个到包括在分布式事务中的每一个资源管理程序相关联。因此。到三个不同的关系数据库管理的请求须要三个事务分支。

每一个事务分支必须由本地资源管理程序提交或者返回。

事务管理程序控制事务的边界。而且负责最后决定应该提交或者返回的所有事务。
这个决定由两个步骤组成,称为Two - Phase Commit Protocol。 



  在第一步骤中,事务管理程序轮询全部包括在分布式事务中的资源管理程序(关系数据库管理)来看看哪个能够准备提交。

假设一个资源管理程序不能提交。它将不响应,而且把事务的特定部分返回。以便数据不被改动。

  在第二步骤中,事务管理程序推断否定响应的资源管理程序中是否有可以返回整个事务的。假设没有否定响应的话。翻译管理程序提交整个事务而且返回结果到应用程序中。 



  开发事项管理程序代码的开发人员必须与全部三个JTA接口有关:UserTransaction、TransactionManager和XAResource,这三个接口都被描写叙述在 



  Sun JTA specification中。JDBC驱动程序开发人员仅仅须要关心XAResource接口。

这个接口是同意一个资源管理程序參与事务的行业标准X/Open XA协议的Java映射。连接XAResource接口的驱动程序组件负责在事务管理程序和资源管理程序之间担任"翻译"的任务。以下的章节提供了XAResource调用的样例。

  JDBC驱动程序和XAResource 



  为了简化XAResource的说明,这些样例说明了一个应用程序在不包括应用程序server和事项管理程序的情况下应该怎样使用JTA。 基本上。这些样例中的应用程序也担任应用程序server和事项管理程序的任务。大部分的企业使用事务管理程序和应用程序server,由于它们可以比一个应用程序更可以高效地管理分布式事务。

然而遵循这些样例,一个应用程序开发人员能够測试在JDBC驱动程序中的JTA支持的健壮性。并且有一些样例可能不是工作在某个特定的数据库上,这是由于关联在数据库上的一些内在的问题。

  在使用JTA之前。你必须首先实现一个Xid类用来标识事务(在一般情况下这将由事务管理程序来处理)。Xid包括三个元素:formatID、gtrid(全局事务标识符)和bqual(分支修饰词标识符)。 



  formatID一般是零,这意味着你将使用OSI CCR(Open Systems Interconnection Commitment, Concurrency和Recovery 标准)来命名。

假设你要是用第二种格式,那么formatID应该大于零。-1值意味着Xid为无效。

  gtrid和bqual能够包括64个字节二进制码来分别标识全局事务和分支事务。唯一的要求是gtrid和bqual必须是全局唯一的。此外,这能够通过使用指定在OSI CCR中的命名规则规范来完毕。

  以下的样例说明Xid的实现:

import javax.transaction.xa.*; 

public class MyXid implements Xid 



 protected int formatId; 

 protected byte gtrid[]; 

 protected byte bqual[]; 

 public MyXid() 

 { 

 } 

 public MyXid(int formatId, byte gtrid[], byte bqual[]) 

 { 

  this.formatId = formatId; 

  this.gtrid = gtrid; 

  this.bqual = bqual; 

 } 



 public int getFormatId() 

 { 

  return formatId; 

 } 



 public byte[] getBranchQualifier() 

 { 

  return bqual; 

 } 



 public byte[] getGlobalTransactionId() 

 { 

  return gtrid; 

 } 













  其次。你须要创建一个你要使用的数据库的数据源: 





public DataSource getDataSource() 

 throws SQLException 

 { 

  SQLServerDataSource xaDS = new 

  com.merant.datadirect.jdbcx.sqlserver.SQLServerDataSource(); 

  xaDS.setDataSourceName("SQLServer"); 

  xaDS.setServerName("server"); 

  xaDS.setPortNumber(1433); 

  xaDS.setSelectMethod("cursor"); 

  return xaDS; 









  例1—这个样例是用“两步提交协议”来提交一个事务分支: 





XADataSource xaDS; 

XAConnection xaCon; 

XAResource xaRes; 

Xid xid; 

Connection con; 

Statement stmt; 

int ret; 

xaDS = getDataSource(); 

xaCon = xaDS.getXAConnection("jdbc_user", "jdbc_password"); 

xaRes = xaCon.getXAResource(); 

con = xaCon.getConnection(); 

stmt = con.createStatement(); 

xid = new MyXid(100, new byte[]{0x01}, new byte[]{0x02}); 

try { 

  xaRes.start(xid, XAResource.TMNOFLAGS); 

  stmt.executeUpdate("insert into test_table values (100)"); 

  xaRes.end(xid, XAResource.TMSUCCESS); 

  ret = xaRes.prepare(xid); 

  if (ret == XAResource.XA_OK) { 

    xaRes.commit(xid, false); 

   } 



catch (XAException e) { 

 e.printStackTrace(); 



finally { 

 stmt.close(); 

 con.close(); 

 xaCon.close(); 









  由于全部这些样例中的初始化代码同样或者很相似,不过一些重要的地方的代码由不同。

  例2—这个样例,与例1相似。说明了一个返回过程: 





xaRes.start(xid, XAResource.TMNOFLAGS); 

stmt.executeUpdate("insert into test_table values (100)"); 

xaRes.end(xid, XAResource.TMSUCCESS); 

ret = xaRes.prepare(xid); 

if (ret == XAResource.XA_OK) { 

 xaRes.rollback(xid); 









  例3—这个样例说明一个分布式事务分支怎样中止,让同样的连接做本地事务处理。以及它们稍后该怎样继续这个分支。 分布式事务的两步提交作用不影响本地事务。 





xid = new MyXid(100, new byte[]{0x01}, new byte[]{0x02}); 

xaRes.start(xid, XAResource.TMNOFLAGS); 

stmt.executeUpdate("insert into test_table values (100)"); 

xaRes.end(xid, XAResource.TMSUSPEND); 

∥这个更新在事务范围之外完毕。所以它不受XA返回影响。 



stmt.executeUpdate("insert into test_table2 values (111)"); 

xaRes.start(xid, XAResource.TMRESUME); 

stmt.executeUpdate("insert into test_table values (200)"); 

xaRes.end(xid, XAResource.TMSUCCESS); 

ret = xaRes.prepare(xid); 



if (ret == XAResource.XA_OK) { 



xaRes.rollback(xid); 











  例4—这个样例说明一个XA资源怎样分担不同的事务。

创建了两个事务分支,可是它们不属于同样的分布式事务。 JTA同意XA资源在第一个分支上做一个两步提交。尽管这个资源仍然与第二个分支相关联。 





xid1 = new MyXid(100, new byte[]{0x01}, new byte[]{0x02}); 

xid2 = new MyXid(100, new byte[]{0x11}, new byte[]{0x22}); 

xaRes.start(xid1, XAResource.TMNOFLAGS); 

stmt.executeUpdate("insert into test_table1 values (100)"); 

xaRes.end(xid1, XAResource.TMSUCCESS); 

xaRes.start(xid2, XAResource.TMNOFLAGS); 

ret = xaRes.prepare(xid1); 

if (ret == XAResource.XA_OK) { 

 xaRes.commit(xid2, false); 



stmt.executeUpdate("insert into test_table2 values (200)"); 

xaRes.end(xid2, XAResource.TMSUCCESS); 

ret = xaRes.prepare(xid2); 

if (ret == XAResource.XA_OK) { 

 xaRes.rollback(xid2); 









  例5—这个样例说明不同的连接上的事务分支怎样连接成为一个单独的分支,假设它们连接到同样的资源管理程序。

这个特点改善了分布式事务的效率。由于它降低了两步提交处理的数目。两个连接到数据库server上的XA将被创建。每一个连接创建它自己的XA资源,正规的JDBC连接和语句。在第二个XA资源開始一个事务分支之前,它将察看是否使用和第一个XA资源使用的是同一个资源管理程序。假设这是实例,它将增加在第一个XA连接上创建的第一个分支,而不是创建一个新的分支。

稍后,这个事务分支使用XA资源来准备和提交。 





xaDS = getDataSource(); 

xaCon1 = xaDS.getXAConnection("jdbc_user", "jdbc_password"); 

xaRes1 = xaCon1.getXAResource(); 

con1 = xaCon1.getConnection(); 

stmt1 = con1.createStatement(); 



xid1 = new MyXid(100, new byte[]{0x01}, new byte[]{0x02}); 

xaRes1.start(xid1, XAResource.TMNOFLAGS); 

stmt1.executeUpdate("insert into test_table1 values (100)"); 

xaRes1.end(xid, XAResource.TMSUCCESS); 

xaCon2 = xaDS.getXAConnection("jdbc_user", "jdbc_password"); 

xaRes2 = xaCon1.getXAResource(); 

con2 = xaCon1.getConnection(); 

stmt2 = con1.createStatement(); 



if (xaRes2.isSameRM(xaRes1)) { 

 xaRes2.start(xid1, XAResource.TMJOIN); 

 stmt2.executeUpdate("insert into test_table2 values (100)"); 

 xaRes2.end(xid1, XAResource.TMSUCCESS); 



else { 

 xid2 = new MyXid(100, new byte[]{0x01}, new byte[]{0x03}); 

 xaRes2.start(xid2, XAResource.TMNOFLAGS); 

 stmt2.executeUpdate("insert into test_table2 values (100)"); 

 xaRes2.end(xid2, XAResource.TMSUCCESS); 

 ret = xaRes2.prepare(xid2); 

 if (ret == XAResource.XA_OK) { 

  xaRes2.commit(xid2, false); 

 } 



ret = xaRes1.prepare(xid1); 

if (ret == XAResource.XA_OK) { 

 xaRes1.commit(xid1, false); 









  例6—这个样例说明在错误恢复的阶段。怎样恢复准备好的或者快要完毕的事务分支。

它首先试图返回每一个分支。假设它失败了,它尝试着让资源管理程序丢掉关于事务的消息。 





MyXid[] xids; 

xids = xaRes.recover(XAResource.TMSTARTRSCAN | XAResource.TMENDRSCAN); 

for (int i=0; xids!=null && i 

 try { 

  xaRes.rollback(xids[i]); 

 } 

 catch (XAException ex) { 

  try { 

   xaRes.forget(xids[i]); 

  } 

 catch (XAException ex1) { 

  System.out.println("rollback/forget failed: " + ex1.errorCode); 

 } 





}

[java][db]JAVA分布式事务原理及应用的更多相关文章

  1. LCN解决分布式事务原理解析+项目实战(原创精华版)

    写在前面: 原创不易,如果觉得不错推荐一下,谢谢! 由于工作需要,公司的微服务项目需解决分布式事务的问题,且由我进行分布式事务框架搭建和整合工作. 那么借此机会好好的将解决分布式事务的内容进行整理一下 ...

  2. 分布式事务(3)---RocketMQ实现分布式事务原理

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

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

      JTA(Java Transaction API)允许应用程序执行分布式事务处理--在两个或多个网络计算机资源上访问并且更新数据. JDBC驱动程序的JTA支持极大地增强了数据访问能力. 本文的目 ...

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

    JTA(Java Transaction API)允许应用程序执行分布式事务处理--在两个或多个网络计算机资源上访问并且更新数据.JDBC驱动程序的JTA支持极大地增强了数据访问能力. 本文的目的是要 ...

  5. java基础之----分布式事务tcc

    最近研究了一下分布式事务框架,ttc,总体感觉还可以,当然前提条件下是你要会使用这个框架.下面分层次讲,尽量让想学习的同学读了这篇文章能加以操作运用.我不想废话,直接上干货. 一.什么是tcc?干什么 ...

  6. MQ关于实现最终一致性分布式事务原理解析

    本文讲述阿里云官方文档中关于通过MQ实现分布式事务最终一致性原理 概念介绍 事务消息:消息队列 MQ 提供类似 X/Open XA 的分布式事务功能,通过消息队列 MQ 事务消息能达到分布式事务的最终 ...

  7. Spring 分布式事务详解

    在学习分布式事务的过程中会遇到以下关键名词: 相关名词: XA :XA规范的目的是允许多个资源(如数据库,应用服务器,消息队列,等等)在同一事务中访问,这样可以使ACID属性跨越应用程序而保持有效.X ...

  8. Dubbo 分布式事务一致性实现

    我觉得事务的管理不应该属于Dubbo框架, Dubbo只需实现可被事务管理即可, 像JDBC和JMS都是可被事务管理的分布式资源, Dubbo只要实现相同的可被事务管理的行为,比如可以回滚, 其它事务 ...

  9. 分布式事务-Sharding 数据库分库分表

      Sharding (转)大型互联网站解决海量数据的常见策略 - - ITeye技术网站 阿里巴巴Cobar架构设计与实践 - 机械机电 - 道客巴巴 阿里分布式数据库服务原理与实践:沈询_文档下载 ...

随机推荐

  1. Linux中断底半部机制

    参考: Linux下半部处理之软中断 linux中断底半部机制 <深入理解Linux内核>软中断/tasklet/工作队列 软中断和tasklet介绍 详解操作系统中断 Linux内核:中 ...

  2. HAL——学习SysTick

    开始: 1.嵌套向量中断寄存器 (NVIC): 嵌套向量中断控制器 (NVIC) 和处理器内核接口紧密配合,可以实现低延迟的中断处理和晚到中断的高效处理.包括内核异常在内的所有中断均通过 NVIC 进 ...

  3. python基础-面向对象(类)

    类 类的定义 >>> class P: ...     pass ... >>> P <class __main__.P at 0x0000000001F4B ...

  4. bootshiro---开源的后台管理框架--基于springboot2+ shiro+jwt的真正rest api资源无状态认证权限管理框架,开发人员无需关注权限问题,后端开发完api,前端页面配置即可

    https://gitee.com/tomsun28/bootshiro

  5. 请编写一个方法,返回某集合的所有非空子集。 给定一个int数组A和数组的大小int n,请返回A的所有非空子集。保证A的元素个数小于等于20,且元素互异。各子集内部从大到小排序,子集之间字典逆序排序,见样例。

    题解:观察测试样例,会发现每个子集的选择规律与二进制((2^n) - 1)到 1 的顺序生成的规律是一致的,样例中n=3,2^n-1=7,用二进制表示为111,其中每一位的1表示数组中的三个数都选择. ...

  6. centos 修改时间 计划任务

    centos 修改时间 计划任务 一,系统时间修改   1 远程连接到centos 或者直接登录系统 #date 查看系统时间 如下图所示 2 #date -s 修改时间 看下面的例子#date -s ...

  7. 一堆Offer怎么选?这样做就不纠结了

    有个朋友,工作了10年左右,春节后换工作,拿了三个Offer(西安): 通信行业的一家研究所,软件开发工程师,月薪7K,承诺有月奖金.年终奖金 一家做大数据的公司,软件开发工程师,月薪15K,13薪 ...

  8. 九度oj 题目1340:小A的计算器

    题目描述: 以往的操作系统内部的数据表示都是二进制方式,小A新写了一个操作系统,系统内部的数据表示为26进制,其中0-25分别由a-z表示. 现在小A要在这个操作系统上实现一个计算器,这个计算器要能实 ...

  9. 九度oj 题目1096:日期差值

    题目描述: 有两个日期,求两个日期之间的天数,如果两个日期是连续的我们规定他们之间的天数为两天 输入: 有多组数据,每组数据有两行,分别表示两个日期,形式为YYYYMMDD 输出: 每组数据输出一行, ...

  10. 14-new和this

    <!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8&quo ...