`

JDBC 分布式事务 基础知识 JTA基本原理

阅读更多

JDBC 分布式事务 基础知识 JTA基本原理

 

1. 分布式事务

 

   事务可分为本地事务和分布式事务(Spring中对应局部事务和全局事务).

   本地事务和分布式事务的区别在于:本地事务只用于处理单一数据源事务(比如单个数据库),

   分布式事务可以处理多种异构的数据源,比如某个业务操作中同时包含了

   JDBC和JMS或者某个操作需要访问多个不同的数据库。

   

   一个事务处理定义了一个工作逻辑单元,要么彻底成功要么不产生任何结果。 

   一个分布式事务处理只是一个在两个或更多网络资源上访问和更新数据的事务处理,

   因此它在那些资源之间必然是等价的。

   

   对于下面这个应用场景: 将用户 A 账户中的 500 元人民币转移到用户 B 的账户中,其操作流程如下 

      1. 将 A 账户中的金额减少 500

      2. 将 B 账户中的金额增加 500

      这两个操作必须保正 ACID 的事务属性:即要么全部成功,要么全部失败;

      假若没有事务保障,用户的账号金额将可能发生问题:

      假如第一步操作成功而第二步失败,那么用户 A 账户中的金额将就减少 500 元而

      用户 B 的账号却没有任何增加(不翼而飞);同样如果第一步出错 而第二步成功,

      那么用户 A 的账户金额不变而用户 B 的账号将增加 500 元(凭空而生)。

      上述任何一种错误都会产生严重的数据不一致问题,

      事务的缺失对于一个稳定的生产系统是不可接受的。

      

   针对上面的应用场景

   (1) 对于本地事务(账户A和账户B存储在同一个数据库中),

   我们需要获取一个普通的Connection连接,然后调用Connection的

   setAutoCommit(false);conn.commit();conn.rollback();等方法即可实现事务控制.

   如代码1所示.

   (2)分布式事务处理(账户A和账户B分别在连接为connA和connB的数据库中),这时

   实现分布式事务,需要事务管理器(TransactionManager),用户事务(UserTransaction,处理分布式事务),

   分布式资源管理器(XADatasource),产生符合特定需求的资源(XAResource,能被TransactionManager管理的).

   其中分布式资源用于产生分布式资源(如connA和connB的数据库连接).通过UserTransaction实现分布式事务.

   如下代码2所示.

   

   代码1(本地事务):

  

public void transferAccount() 
  { 
    Connection conn = null; 
    Statement stmt = null; 
    try
    { 
      conn = getDataSource().getConnection(); 
      // 将自动提交设置为 false,
      // 若设置为 true 则数据库将会把每一次数据更新认定为一个事务并自动提交
      conn.setAutoCommit(false);
     
      stmt = conn.createStatement(); 
      // 将 A 账户中的金额减少 500
      stmt.execute("update t_account set amount = amount - 500 where account_id = 'A'");
      // 将 B 账户中的金额增加 500
      stmt.execute("update t_account set amount = amount + 500 where account_id = 'B'");
     
      // 提交事务
        conn.commit();
      // 事务提交:转账的两步操作同时成功
    } catch(SQLException sqle)
    {      
      try
      { 
        // 发生异常,回滚在本事务中的操做
               conn.rollback();
        // 事务回滚:转账的两步操作完全撤销
                stmt.close(); 
                conn.close(); 
      }
      catch(Exception ignore)
      { 
       
      } 
      sqle.printStackTrace(); 
    } 
  }

 

  

  代码2(分布式事务)

  

public void transferAccount() 
  { 
		
		 UserTransaction userTx = null; 
		 Connection connA = null; 
		 Statement stmtA = null; 
				
		 Connection connB = null; 
		 Statement stmtB = null; 
    
		 try
		 { 
		       // 获得 Transaction 管理对象
			 userTx = (UserTransaction)getContext().lookup("\
			       java:comp/UserTransaction"); 
			 // 从数据库 A 中取得数据库连接
			 connA = getDataSourceA().getConnection(); 
			
			 // 从数据库 B 中取得数据库连接
			 connB = getDataSourceB().getConnection(); 
      
                        // 启动事务
			 userTx.begin();
			
			 // 将 A 账户中的金额减少 500 
			 stmtA = connA.createStatement(); 
			 stmtA.execute("
            update t_account set amount = amount - 500 where account_id = 'A'");
			
			 // 将 B 账户中的金额增加 500 
			 stmtB = connB.createStatement(); 
			 stmtB.execute("\
             update t_account set amount = amount + 500 where account_id = 'B'");
			
			 // 提交事务
			 userTx.commit();
			 // 事务提交:转账的两步操作同时成功(数据库 A 和数据库 B 中的数据被同时更新)
		 } 
		 catch(SQLException sqle)
		 { 
			 try
			 { 
		  	  // 发生异常,回滚在本事务中的操纵
             userTx.rollback();
				 // 事务回滚:转账的两步操作完全撤销 
				 //( 数据库 A 和数据库 B 中的数据更新被同时撤销)
				
				 stmt.close(); 
                 conn.close(); 
				 ... 
			 }catch(Exception ignore)
			 { 
				
			 } 
			 sqle.printStackTrace(); 
			
		 } catch(Exception ne)
		 { 
			 e.printStackTrace(); 
		 } 
	 } 

 

   

 

2. JDBC的分布式事务支持

   

   JDBC规范中定义了XADatasource和XAConnection,用于支持分布式事务处理.

   

   这两个接口与普通的DataSource和Connection的区别:

   普通的DataSource接口的Connection getConnection() 方法返回的就是常用的JDBC数据库连接.

   

   而XADatasource 为分布式事务提供支持的对象。

   

   可以通过 XAResource 对象在分布式事务中利用 XAConnection 对象。

   事务管理器(通常为中间层服务器的一部分)通过 XAResource 对象管理 XAConnection 对象。 

   XADatasource 接口的接口方法 

     XAConnection getXAConnection() 

   返回的XAConnection接口有一个方法XAResource getXAResource(),

   

   public interface XAResource

   

    XAResource 接口是基于 X/Open CAE 规范(分布式事务处理:XA 规范)

    的工业标准 XA 接口的 Java 映射。 

    

    在分布式事务处理 (DTP) 环境中,XA 接口定义资源管理器和事务管理器之间的协定。

    JDBC 驱动程序或 JMS 提供者实现此接口,以支持全局事务与数据库或消息服务连接之间的关联。 

    

    可由应用程序在外部事务管理器控制事务的环境中使用的任何事务资源均可支持 XAResource 接口。

    数据库管理系统就属于此类资源。应用程序可以通过多个数据库连接访问数据。

    通过事务管理器将每个数据库连接作为事务资源添加到列表中。

    事务管理器为参与全局事务的每个连接获取 XAResource。

    事务管理器使用 start 方法建立全局事务与资源之间的关联,

    而使用 end 方法取消事务与资源之间的关联。

    资源管理器负责将全局事务关联到在 start 与 end 方法调用之间对其数据执行的所有工作。 

    

    在事务提交时,事务管理器通知资源管理器根据二阶段提交协议准备、提交或回滚事务。

 

   另外,XAConnection是继承自PooledConnection接口的:

   public interface XAConnectionextends PooledConnection

   

   PooledConnection接口的方法:

   void addConnectionEventListener(ConnectionEventListener listener) 

      注册给定的事件侦听器,以便在此 PooledConnection 

      对象上发生事件时它将得到通知。 

   void addStatementEventListener(StatementEventListener listener) 

      向此 PooledConnection 对象注册一个 StatementEventListener。 

   void close() 

      关闭此 PooledConnection 对象表示的物理连接。 

   Connection getConnection() 

      创建并返回一个 Connection 对象,它是此 PooledConnection 对象表示的物理连接的句柄。 

   void removeConnectionEventListener(ConnectionEventListener listener) 

      从在此 PooledConnection 对象上发生事件时得到通知的组件所组成的列表中移除给定的事件侦听器。 

   void removeStatementEventListener(StatementEventListener listener) 

      从一个组件列表中移除指定的 StatementEventListener,该列表由驱动程序检测到 

      PreparedStatement 已关闭或无效时将获得通知的组件组成。 

 

      



 

 

 

 


 

 

3. JTA,JTS与JOTM

 

   上文中说过,实现分布式事务,需要事务管理器(TransactionManager),用户事务(UserTransaction,处理分布式事务),

   分布式资源管理器(XADatasource),产生符合特定需求的资源(XAResource,能被TransactionManager管理的).

   

   JDBC中只定义了分布式事务所需要的资源(XAResource)机器管理器(XADatasource),

   还有事务管理器(TransactionManager),用户事务(UserTransaction)等则没有涉及,而这部分正是

   JTA主要关注的.

 

   JTA(Java Transaction API)定义了一种标准的API,应用系统由此可以存取各种事务监控。

   

   JTS是CORBA OTS事务监控的基本的实现。JTS规定了事务管理器的实现方式。

   该事务管理器是在高层支持Java Transaction API (JTA)规范,

   并且在较底层实现OMG OTS specification的Java映像。

   JTS事务管理器为 应用服务器、资源管理器、

   以及独立的应用以及通信资源管理器提供了事务服务。

   

   附件:jta-1_1-doc.zip ,是JTA规范的javadoc文档,

   来自:http://www.oracle.com/technetwork/java/javaee/jta/index.html

   JTA的包和类.

   


   JOTM是JTA的一个开源实现,主页:http://jotm.ow2.org/

   

4. 分布式事务的关键角色

 

   资源管理器,主要用于产生符合接口的资源XAResource.比如上文中说的XADatasource.这个是JDBC中的规定的接口,

   各大数据库厂商提供的数据库驱动需要实现这个接口.貌似有的数据库驱动不支持XA规范.还有的数据库驱动提供

   普通版本的JDBC驱动和实现了XA的驱动(支持分布式事务的驱动).

   

   事务管理器,在JTA中定义,TransactionManager,由JTA的实现者负责实现,比如JOTM的实现.

   

   开发人员事务接口:UserTransaction,提供给开发人员的接口,也在JTA中定义.

   

    要理解 JTA 的实现原理首先需要了解其架构:

    它包括事务管理器(Transaction Manager)和一个或多个支持 XA 协议的

    资源管理器 ( Resource Manager ) 两部分, 

    我们可以将资源管理器看做任意类型的持久化数据存储;

    事务管理器则承担着所有事务参与单元的协调与控制。

     

    根据所面向对象的不同,我们可以将 JTA 的事务管理器和资源管理器理解为两个方面:

    面向开发人员的使用接口(事务管理器)和面向服务提供商的实现接口(资源管理器)。

    其中开发接口的主要部分即为上述示例中引用的 UserTransaction 对象,

    开发人员通过此接口在信息系统中实现分布式事务;

    而实现接口则用来规范提供商(如数据库连接提供商)所提供的事务服务,

    它约定了事务的资源管理功能,使得 JTA 可以在异构事务资源之间执行协同沟通。

    

    以数据库为例,IBM 公司提供了实现分布式事务的数据库驱动程序,Oracle 也提供了实现分布式事务的数据库驱动程序, 

    在同时使用 DB2 和 Oracle 两种数据库连接时, JTA 即可以根据约定的接口协调者两种事务资源从而实现分布式事务。

    正是基于统一规范的不同实现使得 JTA 可以协调与控制不同数据库或者 JMS 厂商的事务资源,其架构如下

    

    开发人员使用开发人员接口,实现应用程序对全局事务的支持;各提供商(数据库,JMS 等)

    依据提供商接口的规范提供事务资源管理功能;

    事务管理器( TransactionManager )将应用对分布式事务的使用映射到实际的事务

    资源并在事务资源间进行协调与控制。 

    

    下面,本文将对包括 UserTransaction、Transaction 和 TransactionManager 

    在内的三个主要接口以及其定义的方法进行介绍。

    

    面向开发人员的接口为 UserTransaction (使用方法如上例所示),

    开发人员通常只使用此接口实现 JTA 事务管理,其定义了如下的方法:

    begin()- 开始一个分布式事务,

      在后台 TransactionManager 会创建一个 Transaction 事务对象

    并把此对象通过 ThreadLocale 关联到当前线程上

    commit()- 提交事务

      在后台 TransactionManager 会从当前线程下取出事务对象并把此对象所代表的事务提交

    rollback()- 回滚事务

      在后台 TransactionManager 会从当前线程下取出事务对象并把此对象所代表的事务回滚

    getStatus()- 返回关联到当前线程的分布式事务的状态 

      Status 对象里边定义了所有的事务状态,感兴趣的读者可以参考 API 文档 

    setRollbackOnly()- 标识关联到当前线程的分布式事务将被回滚

    

    面向提供商的实现接口主要涉及到 

    TransactionManager 和 Transaction 两个对象

    

    Transaction 代表了一个物理意义上的事务,

    在开发人员调用 UserTransaction.begin() 方法时 

    TransactionManager 会创建一个 Transaction 事务对象(标志着事务的开始)

    并把此对象通过 ThreadLocale 关联到当前线程。

    UserTransaction 接口中的 commit()、rollback(),getStatus() 

    等方法都将最终委托给 Transaction 类的对应方法执行。

    

    Transaction 接口定义了如下的方法:

      commit()- 协调不同的事务资源共同完成事务的提交

      rollback()- 协调不同的事务资源共同完成事务的回滚

      setRollbackOnly()- 标识关联到当前线程的分布式事务将被回滚

      getStatus()- 返回关联到当前线程的分布式事务的状态

      enListResource(XAResource xaRes, int flag)- 将事务资源加入到当前的事务中

        在上述示例中,在对数据库 A 操作时 其所代表的事务资源将被关联到当前事务中,

        同样,在对数据库 B 操作时其所代表的事务资源也将被关联到当前事务中

      delistResourc(XAResource xaRes, int flag)- 将事务资源从当前事务中删除

      registerSynchronization(Synchronization sync)- 回调接口,

        Hibernate 等 ORM 工具都有自己的事务控制机制来保证事务, 

        但同时它们还需要一种回调机制以便在事务完成时得到通知从而触发一些处理工作,

        如清除缓存等。这就涉及到了 Transaction 的回调接口 registerSynchronization。

        工具可以通过此接口将回调程序注入到事务中,当事务成功提交后,回调程序将被激活。

        

    TransactionManager 本身并不承担实际的事务处理功能,

     它更多的是充当用户接口和实现接口之间的桥梁。

     下面列出了 TransactionManager 中定义的方法,

     可以看到此接口中的大部分事务方法与 UserTransaction 和 Transaction 相同。 

     在开发人员调用 UserTransaction.begin() 方法时 TransactionManager 

     会创建一个 Transaction 事务对象(标志着事务的开始)并把此对象通过 ThreadLocale 关联到当前线程上;

     同样 UserTransaction.commit() 会调用 TransactionManager.commit(), 

     方法将从当前线程下取出事务对象 Transaction 并把此对象所代表的事务提交, 

     即调用 Transaction.commit()

      begin()- 开始事务

      commit()- 提交事务

      rollback()- 回滚事务

      getStatus()- 返回当前事务状态

      setRollbackOnly()

      getTransaction()- 返回关联到当前线程的事务

      setTransactionTimeout(int seconds)- 设置事务超时时间

      resume(Transaction tobj)- 继续当前线程关联的事务

      suspend()- 挂起当前线程关联的事务

      在系统开发过程中会遇到需要将事务资源暂时排除的操作,此时就需要调用 suspend() 方法将当前的事务挂起:

      在此方法后面所做的任何操作将不会被包括在事务中,在非事务性操作完成后调用 resume()以继续事务

      注: 要进行此操作需要获得 TransactionManager 对象, 其获得方式在不同的 J2EE 应用服务器上是不一样的

      下面将通过具体的代码向读者介绍 JTA 实现原理。

      下图列出了示例实现中涉及到的 Java 类,

      其中 UserTransactionImpl 实现了 UserTransaction 接口,

      TransactionManagerImpl 实现了 TransactionManager 接口,

      TransactionImpl 实现了 Transaction 接口

      

      图 2. JTA 实现类图

      

 

     

    清单 3. 开始事务 - UserTransactionImpl implenments UserTransaction

 

    

public void begin() throws NotSupportedException, SystemException 
    { 
       // 将开始事务的操作委托给 TransactionManagerImpl 
       TransactionManagerImpl.singleton().begin(); 
    } 

 

        

    

    清单 4. 开始事务 - TransactionManagerImpl implements TransactionManager

   

    

// 此处 transactionHolder 用于将 Transaction 所代表的事务对象关联到线程上
    private static ThreadLocal<TransactionImpl> transactionHolder 
            = new ThreadLocal<TransactionImpl>(); 
   
    //TransacationMananger 必须维护一个全局对象,因此使用单实例模式实现
    private static TransactionManagerImpl singleton = new TransactionManagerImpl(); 
   
    private TransactionManagerImpl()
    { 
   
    } 
   
    public static TransactionManagerImpl singleton()
    { 
    return singleton; 
    } 
    
    public void begin() throws NotSupportedException, SystemException 
    { 
    //XidImpl 实现了 Xid 接口,其作用是唯一标识一个事务
    XidImpl xid = new XidImpl(); 
    // 创建事务对象,并将对象关联到线程
    TransactionImpl tx = new TransactionImpl(xid); 
   
    transactionHolder.set(tx); 
    } 

 

        

    

    现在我们就可以理解 Transaction 接口上没有定义 begin 方法的原因了:Transaction 对象本身就代表了一个事务,

    在它被创建的时候就表明事务已经开始,因此也就不需要额外定义 begin() 方法了。

     

    清单 5. 提交事务 - UserTransactionImpl implenments UserTransaction

   

      

public void commit() throws RollbackException, HeuristicMixedException, 
    HeuristicRollbackException, SecurityException, 
    IllegalStateException, SystemException 
      { 
    // 检查是否是 Roll back only 事务,如果是回滚事务
      if(rollBackOnly)
      { 
        rollback(); 
   
        return; 
      } 
      else 
      { 
      // 将提交事务的操作委托给 TransactionManagerImpl 
      TransactionManagerImpl.singleton().commit(); 
      } 
    } 

 

    

    清单 6. 提交事务 - TransactionManagerImpl implenments TransactionManager

   

   

 public void commit() throws RollbackException, HeuristicMixedException, 
        HeuristicRollbackException, SecurityException, 
        IllegalStateException, SystemException 
    { 
   
       // 取得当前事务所关联的事务并通过其 commit 方法提交
       TransactionImpl tx = transactionHolder.get(); 
       tx.commit(); 
    } 

 

       

    

    同理, rollback、getStatus、setRollbackOnly 等方法也采用了与 commit() 相同的方式实现。 

    UserTransaction 对象不会对事务进行任何控制, 所有的事务方法都是通过 TransactionManager 

    传递到实际的事务资源即 Transaction 对象上。

    上述示例演示了 JTA 事务的处理过程,

    下面将为您展示事务资源(数据库连接,JMS)是如何以透明的方式加入到 JTA 事务中的。

    首先需要明确的一点是,在 JTA 事务 代码中获得的数据库源 ( DataSource ) 必须是支持分布式事务的。

    在如下的代码示例中,尽管所有的数据库操作都被包含在了 JTA 事务中,但是因为 MySql 的数据库连接是通过本地方式获得的,

    对 MySql 的任何更新将不会被自动包含在全局事务中。

    

    清单 7. JTA 事务处理

   

    

 public void transferAccount() 
     { 
   
    UserTransaction userTx = null; 
    Connection mySqlConnection = null; 
    Statement mySqlStat = null; 
   
    Connection connB = null; 
    Statement stmtB = null; 
        
    try
    { 
      // 获得 Transaction 管理对象
    userTx = (UserTransaction)getContext().lookup("java:comp/UserTransaction");
    // 以本地方式获得 mySql 数据库连接
    mySqlConnection = DriverManager.getConnection("localhost:1111"); 
   
    // 从数据库 B 中取得数据库连接, getDataSourceB 返回应用服务器的数据源
    connB = getDataSourceB().getConnection(); 
          
           // 启动事务
    userTx.begin();
   
    // 将 A 账户中的金额减少 500 
    //mySqlConnection 是从本地获得的数据库连接,不会被包含在全局事务中
    mySqlStat = mySqlConnection.createStatement(); 
    mySqlStat.execute("
                 update t_account set amount = amount - 500 where account_id = 'A'");
   
    //connB 是从应用服务器得的数据库连接,会被包含在全局事务中
    stmtB = connB.createStatement(); 
    stmtB.execute("
                 update t_account set amount = amount + 500 where account_id = 'B'");
   
    // 事务提交:connB 的操作被提交,mySqlConnection 的操作不会被提交
    userTx.commit();
    
    } catch(SQLException sqle){ 
    // 处理异常代码
    } catch(Exception ne){ 
    e.printStackTrace(); 
    } 
    } 

  

    

    为什么必须从支持事务的数据源中获得的数据库连接才支持分布式事务呢?

    其实支持事务的数据源与普通的数据源是不同的,它实现了额外的 XADataSource 接口。

    我们可以简单的将 XADataSource 理解为普通的数据源(继承了 java.sql.PooledConnection),

    只是它为支持分布式事务而增加了 getXAResource 方法。

    另外,由 XADataSource 返回的数据库连接与普通连接也是不同的,

    此连接除了实现 java.sql.Connection 定义的所有功能之外还实现了 XAConnection 接口。

    我们可以把 XAConnection 理解为普通的数据库连接,它支持所有 JDBC 规范的数据库操作,

    不同之处在于 XAConnection 增加了对分布式事务的支持。

    通过下面的类图读者可以对这几个接口的关系有所了解:

    

    图 3. 事务资源类图

    

 

    

    应用程序从支持分布式事务的数据源获得的数据库连接是 XAConnection 接口的实现,

    而由此数据库连接创建的会话(Statement)也为了支持分布式事务而增加了功能,如下代码所示:

     

    清单 8. JTA 事务资源处理

   

     

public void transferAccount() 
     { 
   
    UserTransaction userTx = null; 
   
    Connection conn = null; 
    Statement stmt = null; 
        
    try
    { 
      // 获得 Transaction 管理对象
    userTx = (UserTransaction)getContext().lookup("java:comp/UserTransaction"); 
    
    // 从数据库中取得数据库连接, getDataSourceB 返回支持分布式事务的数据源
    conn = getDataSourceB().getConnection(); 
           // 会话 stmt 已经为支持分布式事务进行了功能增强
    stmt = conn.createStatement(); 
   
           // 启动事务
    userTx.begin();
           stmt.execute("update t_account ... where account_id = 'A'"); 
    userTx.commit();
    
    } catch(SQLException sqle){ 
    // 处理异常代码
    } catch(Exception ne){ 
    e.printStackTrace(); 
    } 
    } 

 

   

    

    我们来看一下由 XAConnection 数据库连接创建的会话(Statement)部分的代码实现

    (不同的 JTA 提供商会有不同的实现方式,此处代码示例只是向您演示事务资源是如何被自动加入到事务中)。 

    我们以会话对象的 execute 方法为例,通过在方法开始部分增加对 associateWithTransactionIfNecessary 方法的调用,

    即可以保证在 JTA 事务期间,对任何数据库连接的操作都会被透明的加入到事务中。

     

    清单 9. 将事务资源自动关联到事务对象 - XAStatement implements Statement

   

     

public void execute(String sql) 
     { 
         // 对于每次数据库操作都检查此会话所在的数据库连接是否已经被加入到事务中
    associateWithTransactionIfNecessary(); 
    
    try
    { 
              // 处理数据库操作的代码
         .... 
    
    } catch(SQLException sqle){ 
    // 处理异常代码
    } catch(Exception ne){ 
    e.printStackTrace(); 
    } 
    } 
    
     public void associateWithTransactionIfNecessary()
     { 
        
    // 获得 TransactionManager 
    TransactionManager tm = getTransactionManager(); 
    
                    Transaction tx = tm.getTransaction();
            // 检查当前线程是否有分布式事务
           if(tx != null){ 
    // 在分布式事务内,通过 tx 对象判断当前数据连接是否已经被包含在事务中,
    //如果不是那么将此连接加入到事务中
    Connection conn = this.getConnection(); 
    //tx.hasCurrentResource, xaConn.getDataSource() 不是标准的 JTA 
    // 接口方法,是为了实现分布式事务而增加的自定义方法
    if(!tx.hasCurrentResource(conn)){ 
        XAConnection xaConn = (XAConnection)conn; 
        XADataSource xaSource = xaConn.getDataSource(); 
   
        // 调用 Transaction 的接口方法,将数据库事务资源加入到当前事务中
        tx.enListResource(xaSource.getXAResource(), 1);
            } 
            } 
    }

 

   

    

    XAResource 与 Xid: XAResource 是 Distributed Transaction Processing: The XA Specification 标准的 Java 实现,

    它是对底层事务资源的抽象,定义了分布式事务处理过程中事务管理器和资源管理器之间的协议,

    各事务资源提供商(如 JDBC 驱动,JMS)将提供此接口的实现。

    使用此接口,开发人员可以通过自己的编程实现分布式事务处理,

    但这些通常都是由应用服务器实现的(服务器自带实现更加高效,稳定) 为了说明,

    我们将举例说明他的使用方式。

    

    在使用分布式事务之前,为了区分事务使之不发生混淆,必须实现一个 Xid 类用来标识事务,

    可以把 Xid 想象成事务的一个标志符,每次在新事务创建是都会为事务分配一个 Xid,

    Xid 包含三个元素:formatID、gtrid(全局事务标识符)和 bqual(分支修饰词标识符)。 

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

    如果你要使用另外一种格式,那么 formatID 应该大于零,-1 值意味着 Xid 为无效。

    gtrid 和 bqual 分别包含 64 个字节二进制码来分别标识全局事务和分支事务, 

    唯一的要求是 gtrid 和 bqual 必须是全局唯一的。

    

    XAResource 接口中主要定义了如下方法:

    commit()- 提交事务

    isSameRM(XAResource xares)- 检查当前的 XAResource 与参数是否同一事务资源

    prepare()- 通知资源管理器准备事务的提交工作

    rollback()- 通知资源管理器回滚事务

    在事务被提交时,Transaction 对象会收集所有被当前事务包含的 XAResource 资源,

    然后调用资源的提交方法,如下代码所示:

    

    清单 10. 提交事务 - TransactionImpl implements Transaction

   

    

public void commit() throws RollbackException, HeuristicMixedException, 
    HeuristicRollbackException, SecurityException, 
    IllegalStateException, SystemException 
    { 
   
    // 得到当前事务中的所有事务资源
       List<XAResource> list = getAllEnlistedResouces(); 
   
    // 通知所有的事务资源管理器,准备提交事务
     // 对于生产级别的实现,此处需要进行额外处理以处理某些资源准备过程中出现的异常
    for(XAResource xa : list)
    { 
    xa.prepare(); 
    } 
   
      // 所有事务性资源,提交事务
      for(XAResource xa : list)
      { 
         xa.commit(); 
       } 
    } 

 

 

 参考: JTA深度历险

 

 JOTM API

  • 大小: 44.6 KB
  • 大小: 96.6 KB
  • 大小: 85.8 KB
  • 大小: 106.3 KB
  • 大小: 107.1 KB
  • 大小: 104.3 KB
  • 大小: 43.2 KB
  • 大小: 42.1 KB
分享到:
评论
1 楼 M_drm 2015-05-27  
学习了,赞

相关推荐

Global site tag (gtag.js) - Google Analytics