Spring事务管理之HibernateTransactionManager

来源:互联网 发布:mysql offset用法 编辑:程序博客网 时间:2024/03/29 06:51

对于Spring的事务管理,我们一般只知道是采用AOP(面向切面)的方式进行事务管理。也就是说,在执行Service方法时,Spring会通过动态代理的方式去获取执行service方法的对象,然后在执行具体的业务方法之前和之后,可以加入spring的事务管理。

问题来了,既然要进行事务管理,spring必须要拿到service方法中使用的connection对象,在Hibernate中也就是session对象。本章节就为大家揭开Spring是如何获取到同一个connection对象的。这里我们拿HibernateTransactionManager来举例。

<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">            <property name="sessionFactory" ref="sessionFactory" /></bean>

在service中的如何获取session对象,一般是用SessionFactory.getCurrentSession()。我们来看一下SessionFactory中的getCurrentSession()具体实现方法

private final transient CurrentSessionContext currentSessionContext;public org.hibernate.classic.Session getCurrentSession() throws HibernateException {        if ( currentSessionContext == null ) {            throw new HibernateException( "No CurrentSessionContext configured!" );        }        return currentSessionContext.currentSession();    }

可以看出返回的是从CurrentSessionContext中获取当前的session,再看其中一种实现方式ThreadLocalSessionContext。

    private static final ThreadLocal context = new ThreadLocal();    public final Session currentSession() throws HibernateException {        Session current = existingSession( factory );        if (current == null) {            current = buildOrObtainSession();            // register a cleanup synch            current.getTransaction().registerSynchronization( buildCleanupSynch() );            // wrap the session in the transaction-protection proxy            if ( needsWrapping( current ) ) {                current = wrap( current );            }            // then bind it            doBind( current, factory );        }        return current;    }    private static Session existingSession(SessionFactory factory) {        Map sessionMap = sessionMap();        if ( sessionMap == null ) {            return null;        }        else {            return ( Session ) sessionMap.get( factory );        }    }    protected static Map sessionMap() {        return ( Map ) context.get();    }

上面的代码中有一个静态成员变量context,从这几个方法中大致可以看出,session实际上是从一个名为context的ThreadLocal静态变量中获取当前的线程中的session。假如是session不存在,则将产生一个新的Session然后在绑定到ThreadLocal中。

以上是调用SessionFactory.getCurrentSession()是怎么返回session的代码解读。然后再来读一下Spring的HibernateTransactionManager的代码。

找到doGetTransaction()方法,这个方法是获取事务管理器。其中可以看到假如sessionHolder为空,则获取session对象也是调用SessionFactory中的getCurrentSession()方法。

@Override    protected Object doGetTransaction() {        HibernateTransactionObject txObject = new HibernateTransactionObject();        txObject.setSavepointAllowed(isNestedTransactionAllowed());        SessionHolder sessionHolder =                (SessionHolder) TransactionSynchronizationManager.getResource(getSessionFactory());        if (sessionHolder != null) {            if (logger.isDebugEnabled()) {                logger.debug("Found thread-bound Session [" +                        SessionFactoryUtils.toString(sessionHolder.getSession()) + "] for Hibernate transaction");            }            txObject.setSessionHolder(sessionHolder);        }        else if (this.hibernateManagedSession) {            try {                //获取session                Session session = getSessionFactory().getCurrentSession();                if (logger.isDebugEnabled()) {                    logger.debug("Found Hibernate-managed Session [" +                            SessionFactoryUtils.toString(session) + "] for Spring-managed transaction");                }                txObject.setExistingSession(session);            }            catch (HibernateException ex) {                throw new DataAccessResourceFailureException(                        "Could not obtain Hibernate-managed Session for Spring-managed transaction", ex);            }        }        if (getDataSource() != null) {            ConnectionHolder conHolder = (ConnectionHolder)                    TransactionSynchronizationManager.getResource(getDataSource());            txObject.setConnectionHolder(conHolder);        }        return txObject;    }

结论:在一个线程中,不论何时获取当前的Session都会是同于一个对象。
(注:ThreadLocal这里解释一下,是为每个线程都拷贝一份独立的对象,每个线程之间互不干扰。)

用一个流程图来表示一下:
这里写图片描述

1 0
原创粉丝点击