(转)TransactionSynchronizationManager理解

http://blog.sina.com.cn/s/blog_4ae2ef25010008ai.html
发现
 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 ThreadLocal currentTransactionName = new ThreadLocal();
 private static final ThreadLocal currentTransactionReadOnly = new ThreadLocal();
 private static final ThreadLocal actualTransactionActive = new ThreadLocal(); ……
}
再看看方法SessionHolder的理解

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

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

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

    public Long addLineItem(Long orderId, LineItem lineItem){

       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 中更加清晰了。

你可能感兴趣的:(收藏文章)