TransactionSynchronizationManager理解

发现
 protected void setUp()throws Exception
    {
      super.setUp();
      context= new FileSystemXmlApplicationContext(springConfigFile);
     if(bHoldSession)
    {
  sessionFactory =(SessionFactory) context.getBean("sessionFactory");
  Session session =SessionFactoryUtils.getSession(sessionFactory, true);
  TransactionSynchronizationManager.bindResource(sessionFactory,new SessionHolder(session));
    }
 }
对  TransactionSynchronizationManager.bindResource(sessionFactory,new SessionHolder(session));的理解如下:
在调用一个需要事务的组件的时候,管理器首先判断当前调用(即当前线程)有没有一个事务,如果没有事务则启动一个事务,并把事务与当前线程绑定。Spring使用TransactionSynchronizationManager的bindResource方法将当前线程与一个事务绑定,采用的方式就是ThreadLocal,这可以从TransactionSynchronizationManager类的代码看出。
public abstract class TransactionSynchronizationManager
{
 ……
 private static final ThreadLocalcurrentTransactionName = new ThreadLocal();
 private static final ThreadLocalcurrentTransactionReadOnly = new ThreadLocal();
 private static final ThreadLocalactualTransactionActive = newThreadLocal(); ……
}
再看看方法SessionHolder的理解

先看一段代码:
    Connectionconn = Conn.getConnection();
   conn.setAutoCommit(false);
    ……..
   ……...
   conn.rollback();
   conn.commit();

   数据库的事务是针对 Connection 的。

   接着再看一段代码:( spring 中事务的一段学习代码,这段代码是把spring 和 hibernate结合在一起的,增加了理解上的难度,因为我的出发点一开始不要hibernate ,就光用 jdbc来进行数据库事务,但是没有其他好的代码,就这样吧)

   public Long addLineItem(Long orderId, LineItemlineItem){

      log("OrderListDAOHibernate.addLineItem : Start...");

      OrderList orderList = (OrderList)getHibernateTemplate().load(OrderList.class, orderId);

      lineItem.setOrderList(orderList);

      getHibernateTemplate().saveOrUpdate(lineItem);

      getHibernateTemplate().saveOrUpdate(orderList);

      log("OrderListDAOHibernate.addLineItem : Ending...");

      return lineItem.getId();

   }

   在这个代码的配置文件中,把 addLineItem做为一个切入点,进行事务,也就是说,在 addLineItem的外面,再包上一层事务的外壳。

   但是这个时候,问题出来了,事务是针对 Connection的,而上面的两个连续的 HibernateTemplate 执行的 saveOrUpdate 中的Connection 必须是一致才能用事务, spring怎么做到这一点的呢?(这个问题也就是在找 spring的事务例子前,我想的 spring 中用 jdbc 来进行事务,怎么样让Connection 保持一致呢?但是没有 jdbc 的例子,只有整合 hibernate或者 ibatis 的例子,但是,我想,原理是一样的吧。)

   解决问题的思路: HibernateTemplate 中的 Connection必定一致。那么就从 HibernateTemplate 入手。

    看spring 的源代码,既然是 Hibernate ,那么,就没有 Connection给你看,只有 Session ,由 Session 来管理 Connection,那么用事务来控制的话,这个 Session必定在所有该事务中是一致的。于是在 HibernateTemplate中找到:
protected Session getSession() {

      if (isAlwaysUseNewSession()) {

return SessionFactoryUtils.getNewSession(getSessionFactory(),getEntityInterceptor());

      }

      else if (!isAllowCreate()) {

return SessionFactoryUtils.getSession(getSessionFactory(),false);

      }

      else {

return SessionFactoryUtils.getSession(

                 getSessionFactory(), getEntityInterceptor(),getJdbcExceptionTranslator());

      }

    }

 

看来在 SessionFactoryUtils 里面,接着在SessionFactoryUtils.getSession 中找:

这个方法太长了,太复杂了,从简,发现了非常关键的一点:

SessionHolder sessionHolder = (SessionHolder)TransactionSynchronizationManager.getResource(sessionFactory);

假如 sessionHolder不等于空,说明,在事务中有这样一个还没有 commit 的 session,那么就返回这个 session ,假如等于空,新建一个 session,并且在事务里加入这个 session。这段代码的意思大概是这样,太繁杂了,只能猜,也肯定是如此。

 

再看 getHibernateTemplate() 方法来自继承 HibernateDaoSupport,看了电子书《 spring-reference 》的第九章“ Dao 支持”, Dao的支持类可以有好多,如: JdbcDaoSupport , HibernateDaoSupport ,JdoDaoSupport 等等。

 

既然前面一开始就是从 jdbc 的 spring事务控制引起的,那么看到了同样的HibernateDaoSupport---JdbcDaoSupport ,那么 JdbcDaoSupport 也应该有getJdbcTemplate() 这个方法,并且返回 JdbcTemplate 这个类。
果然如此。
于是剖析 JdbcTemplate 是不是和 HibernateTemplate一样。果然一样。
注意到:

Connection con =DataSourceUtils.getConnection(getDataSource());

Connection 是从 DataSourceUtils.getConnection() 来的,继续跟踪DataSourceUtils.getConnection() 。

找到:

ConnectionHolder conHolder = (ConnectionHolder)TransactionSynchronizationManager.getResource(dataSource);  

和 Hibernate 中的一模一样,因为没有了 session 的封装,条理在jdbc 中更加清晰了。

你可能感兴趣的:(Java技术)