日期:2014-05-16  浏览次数:20626 次

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和XAConnectio