Spring事务管理之HibernateTransactionManager

本文介绍了Spring如何利用AOP进行事务管理,并以HibernateTransactionManager为例,深入解析Spring如何获取并管理Hibernate的session对象。通过SessionFactory.getCurrentSession()方法结合ThreadLocal,Spring确保在一个线程中始终使用同一个session进行事务操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

对于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这里解释一下,是为每个线程都拷贝一份独立的对象,每个线程之间互不干扰。)

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值