spring本地事务与JTA事务实现解析

Posted on 2005-10-22 22:57 publisher luo 阅读(10164) 评论(2)  编辑  收藏 所属分类: 项目问题解决

      大家都知道spring支持两种事务,一种是本地连接事务(使用DataSourceTransactionManager),一种是JTA事务(使用JtaTransactionManager)。并且支持声明式事务和编程式事务两种方式。采用声明式事务使用AOP方式的TransactionProxyFactoryBean代理工厂类。
      JTA事务实现相对较好理解,在执行实际类的符合模式的方法时,代理类通过在连接点前后插入预处理过程(开始事务)和后处理过程(commit或rollbak)即可。因为JTA事务支持两阶段提交所以在代码中启动多少个连接(不同的connection)都能保证事务最终提交或者回滚。可是本地连接事务是如何实现的呢?因为必须后面的dao层必须使用的同一个连接才能保证事务正常提交和回滚,在业务逻辑层可以调用dao层的多个类的多个方法,每个方法如果显式的将connection做为参数传入到还可以,但是这样connection就要出现调用的在业务逻辑层,而且dao的每个方法还要有个connection参数比较难看,而且开发人员要关注事务,这样就没有达到开发人员只要关注业务逻辑即可的要求。 
      web应用,各个类都要在多线程环境下运行,所以每个方法要保证线程安全,这样,不在dao方法中加参数而是在dao类中加入connection属性也就不可取了,怎么办?查看一下JdbcTemplate类,在执行每个方法需要数据库连接时都使用了DataSourceUtils.getConnection(getDataSource())方法?难道每回都从数据源里面取一条连接?不可能,这样事务肯定没法实现,可是怎么能保证取的是一条连接呢?对了是不是采用本地线程呀(TreadLocal),因为一段事务都是在一个线程中完成,所以只要在事务开始的时候将connection存放在本地线程中,然后事务过程中从本地线程中取出connection,直到事务结束即可。不错,这样只需要在每个dao方法的取数据库连接的方法中有个事务状态的判断即可。不错看看spring是不是这样实现的?果然如此,DataSourceUtils.getConnection(DataSource)方法调用doGetConnection()方法,方法内容如下:
public static Connection doGetConnection(DataSource dataSource) throws SQLException {
  Assert.notNull(dataSource, "No DataSource specified");

  ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager.getResource(dataSource);
  if (conHolder != null) {
   conHolder.requested();
   return conHolder.getConnection();
  }

  logger.debug("Fetching JDBC Connection from DataSource");
  Connection con = dataSource.getConnection();

  if (TransactionSynchronizationManager.isSynchronizationActive()) {
   logger.debug("Registering transaction synchronization for JDBC Connection");
   // Use same Connection for further JDBC actions within the transaction.
   // Thread-bound object will get removed by synchronization at transaction completion.
   conHolder = new ConnectionHolder(con);
   conHolder.setSynchronizedWithTransaction(true);
   conHolder.requested();
   TransactionSynchronizationManager.registerSynchronization(
     new ConnectionSynchronization(conHolder, dataSource));
   TransactionSynchronizationManager.bindResource(dataSource, conHolder);
  }

  return con;
 }
conHolder?TransactionSynchronizationManager?很象呀,继续看看TransactionSynchronizationManager类果真如此,里面使用TreadLocal来保存数据连接和事务状态。原来如此,代码里的各个层没有特殊需要都不用再出现事务了,程序开发人员只要关注业务就可以了,不用再劳心编写事务代码了。

Feedback

# re: spring本地事务与JTA事务实现解析  回复  更多评论   

2005-12-08 08:47 by seagoer
不错,我也一致疑惑 对于本地事务,难道spring实现了自己的jta,dao层每个方法都独自获得连接来处理,看起来好像确实是使用本地线程来处理的。

# re: spring本地事务与JTA事务实现解析  回复  更多评论   

2006-01-11 14:17 by barry
呵呵。我也刚刚想到这个问题。
查看了一下spring doc。
如果在代码中直接使用了DataSource.getConnetction()的方式(比如遗留代码),还可以通过设置一个TransactionAwareDataSourceProxy来代理DataSource。

只有注册用户登录后才能发表评论。


网站导航:
 

posts - 9, comments - 27, trackbacks - 0, articles - 19

Copyright © publisher luo