spring管理hibernate事务2

背景

上一章详细的描述了spring如何通过代理方法上的属性生成TrasactionAttribute,继而查找TrasactionManager。详细介绍了TrasactionAttribute的结构,查找TrasactionManager的流程,生成TrasactionAttribute的流程,延伸讲解了TransactionInterceptor和TransactionAspectSupport两个类的关系,spring如何将AOP模块和事务模块结合起来,其核心思想。大家将来在扩展spring AOP时,可以借鉴spring的思想。在抽象类Support处理核心业务,另一个类比如MybuzzInterceptor实现spring AOP接口,同时继承TransactionAspectSupport,这样MybuzzInterceptor就只是AOP和核心业务的桥梁,解耦AOP模块和你的业务模块。

流程

TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification)

上一步已经生成了TrasactionManager,TrasactionAttribute,这一步就是如何使用这些数据。比如hibernate增删查改数据库时,会生成session,而这步就是要执行该行为。TransactionInfo,spring管理事务的核心类,先分析该类。transactionManager,transactionAttribute,joinpointIdentification,这三个属性在上步已经生成了;oldTransactionInfo,上个对象的引用,说明这是一个链表结构,有链表说明要循环遍历?为何要这么使用,大家可以思考下!提示:spring管理的service嵌套调用,涉及到spring事务的传播特性。

    protected final class TransactionInfo {

        private final PlatformTransactionManager transactionManager;

        private final TransactionAttribute transactionAttribute;

        private final String joinpointIdentification;

        private TransactionStatus transactionStatus;

        private TransactionInfo oldTransactionInfo;
        public TransactionInfo(PlatformTransactionManager transactionManager,
                TransactionAttribute transactionAttribute, String joinpointIdentification) {
            this.transactionManager = transactionManager;
            this.transactionAttribute = transactionAttribute;
            this.joinpointIdentification = joinpointIdentification;
        }

再看如何生成TransactionInfo。

protected TransactionInfo createTransactionIfNecessary(
if (txAttr != null && txAttr.getName() == null) {
            txAttr = new DelegatingTransactionAttribute(txAttr) {
                @Override
                public String getName() {
                    return joinpointIdentification;
                }
            };
        }
}

没有定义事务名时,以joinpointIdentification来命名。又一次使用了匿名内部类,其目的是为了生成TransactionAttribute.name,DelegatingTransactionAttribute继承了DelegatingTransactionDefinition的抽象类,实现了TransactionAttribute接口。TransactionDefine接口定义了getName()方法,

生成TrasactionStatus

TrasactionStatus 是spring事务模块的核心接口,我们先看接口定义:

public interface TransactionStatus extends SavepointManager, Flushable {
    boolean isNewTransaction();
    boolean hasSavepoint();
    void setRollbackOnly();
    boolean isRollbackOnly();
    void flush();
    boolean isCompleted();
}
public interface SavepointManager {
    Object createSavepoint() throws TransactionException;
    void rollbackToSavepoint(Object savepoint) throws TransactionException;
    void releaseSavepoint(Object savepoint) throws TransactionException;

}

通过接口方法,也大致能推测与事务的执行状态有关,比如isCompleted可能会影响事务执行完毕后的清理。

获取事务的核心代码如下,这是org.springframework.orm.hibernate5.HibernateTransactionManager生成事务的代码:

    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 [" + sessionHolder.getSession() + "] for Hibernate transaction");
            }
            txObject.setSessionHolder(sessionHolder);
        }
        else if (this.hibernateManagedSession) {
            try {
                Session session = this.sessionFactory.getCurrentSession();
                if (logger.isDebugEnabled()) {
                    logger.debug("Found Hibernate-managed Session [" + 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;
    }
  1. 生成HibernateTransactionObject,如果该transactionManager支持嵌套式事务,HibernateTransactionObject即支持设置savePoint。
  2. 生成sessionHolder,根据变量名,推测他可能是真实session(即Hibernate实现的session)的句柄,代码如下:
    SessionHolder sessionHolder =
    (SessionHolder) TransactionSynchronizationManager.getResource(getSessionFactory())

spring配置文件中配置transactionManager,注入了sessionFactory,getSessionFactory()就是获取注入的sessionFactory。大家这时就明白transactionManager和sessionFactory的关系了吧。getResource()方法是TransactionSynchronizationManager类(抽象类)的静态方法。
TransactionSynchronizationManager类中定义了线程变量ThreadLocal<Map<Object, Object>>=new NamedThreadLocal<Map<Object, Object>>("Transactional resources"),

private static Object doGetResource(Object actualKey) {
        Map<Object, Object> map = resources.get();
        if (map == null) {
            return null;
        }
        Object value = map.get(actualKey);
        // Transparently remove ResourceHolder that was marked as void...
        if (value instanceof ResourceHolder && ((ResourceHolder) value).isVoid()) {
            map.remove(actualKey);
            // Remove entire ThreadLocal if empty...
            if (map.isEmpty()) {
                resources.remove();
            }
            value = null;
        }
        return value;
    }

以上是getResource核心代码,该方法就是根据actualKey作为key从线程变量中查对应的value。简单来说就是在某一步会将sessionFactory放入到这个线程变量中。在调试过程中,当前值为null,所以返回的sessionHolder也为null


sessionHolder为null,判断当前是否为hibernate管理事务,如果是,则调用sessionFactory.getCurrentSession()。


获取connectionHolder,同事务,不过是以datasource作为key,当前返回的仍然是null。
以上就是doGetTransaction()方法的整个过程,可以分为3步。

  1. 生成HibernateTransactionObject
  2. 在线程变量中获取sessionHolder,并设置到HibernateTransactionObject
  3. 在线程变量中获取connectionHolder,并设置到HibernateTransactionObject

判断该事务是否是正在使用的事务,判断条件
txObject.hasSpringManagedTransaction() ||
(this.hibernateManagedSession && txObject.hasHibernateManagedTransaction())
在spring 管理事务模式下,就是sessionHolder是否为Null, null就是新事务,否则就是当前事务。
如果是当前事务,走handleExistingTransaction(definition, transaction, debugEnabled),后续再看。
非当前正在使用的事务:即要创建新事务属性,因为sessionHolder,connectionHolder都是null
判断事务属性的传播特性是否为PROPAGATION_MANDATORY(当前必须存在在事务),如果是,抛出异常,因为当前不存在事务
判断传播特性是否为PROPAGATION_REQUIRED或者PROPAGATION_REQUIRES_NEW或者PROPAGATION_NESTED(他们的共同点是创建新事务)
我配置的是PROPAGATION_REQUIRED,以下该分支下相应代码

SuspendedResourcesHolder suspendedResources = suspend(null);
            if (debugEnabled) {
                logger.debug("Creating new transaction with name [" + definition.getName() + "]: " + definition);
            }
            try {
                boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
                DefaultTransactionStatus status = newTransactionStatus(
                        definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
                doBegin(transaction, definition);
                prepareSynchronization(status, definition);
                return status;
            }
            catch (RuntimeException ex) {
                resume(null, suspendedResources);
                throw ex;
            }
            catch (Error err) {
                resume(null, suspendedResources);
                throw err;
            }

以上代码暂不考虑,暂时不明白
生成DefaultTransactionStatus,这就是本章最终返回的结果,这是最外层的方法

status = tm.getTransaction(txAttr)
Session newSession = (entityInterceptor != null ?
                        getSessionFactory().withOptions().interceptor(entityInterceptor).openSession() :
                        getSessionFactory().openSession());

openSession说明了是打开一个新的session,HibernateTransactionObject生成sesssionHolder,holder保存session
如果配置的事务属性是readOnly并且是新事务,则将session.setFlushMode(FlushMode.MANUAL),如果是readOnly,但不是新事务,那么就重新设置flushMode。
当配置事务超时时间为默认-1时,则使用纯粹的hibernate事务,

Transaction hibTx = session.beginTransaction();

保存真正的事务对象到sessionHolder
如果dataSource不为空,通过session获取物理连接connection,保存到connectionHolder,并以dataSource做为key,connectionHolder作为value,保存到之前介绍的线程变量resources中。
同时将sessionHolder作为value,sessionFactory作为key,也保存到resources中

protected void prepareSynchronization(DefaultTransactionStatus status, TransactionDefinition definition) {
        if (status.isNewSynchronization()) {
            TransactionSynchronizationManager.setActualTransactionActive(status.hasTransaction());
            TransactionSynchronizationManager.setCurrentTransactionIsolationLevel(
                    definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT ?
                            definition.getIsolationLevel() : null);
            TransactionSynchronizationManager.setCurrentTransactionReadOnly(definition.isReadOnly());
            TransactionSynchronizationManager.setCurrentTransactionName(definition.getName());
            TransactionSynchronizationManager.initSynchronization();
        }
    }

该方法只有在新生成的事务才会生效,都是配置到线程变量中
以上就是获得TransactioStatus的具体步骤。

  1. 生成HibernateTransactionObject
  2. 以sessionFactory为key到线程变量resource中查sessionHolder,以datasource为key到线程变量resource中查connectionHolder,如果没有,表示要生成新的事务,走步骤3
  3. 调用hibernate的sessionFactory.openSession()创建新的session,保存到sessionHolder,同时生成transaction,将sessionHolder和connectionHolder都保存到resource中
  4. session中调用beginTransaction()启动事务,同时将transaction保存到sessionHolder中

生成TransactionStatus后,然后在生成TransactionInfo,该对象相当于集中保存了TransactionStatus,transactionAttribute,TransactionPlateformManager,之后存到线程变量transactionInfoHolder中,TransactionInfo是个链表结构,在transactionInfoHolder是链表头指针,bindThread就是首部插入节点。

protected TransactionInfo prepareTransactionInfo(PlatformTransactionManager tm,
            TransactionAttribute txAttr, String joinpointIdentification, TransactionStatus status) {

        TransactionInfo txInfo = new TransactionInfo(tm, txAttr, joinpointIdentification);
        if (txAttr != null) {
            // We need a transaction for this method
            if (logger.isTraceEnabled()) {
                logger.trace("Getting transaction for [" + txInfo.getJoinpointIdentification() + "]");
            }
            // The transaction manager will flag an error if an incompatible tx already exists
            txInfo.newTransactionStatus(status);
        }
        else {
            // The TransactionInfo.hasTransaction() method will return
            // false. We created it only to preserve the integrity of
            // the ThreadLocal stack maintained in this class.
            if (logger.isTraceEnabled())
                logger.trace("Don't need to create transaction for [" + joinpointIdentification +
                        "]: This method isn't transactional.");
        }

        // We always bind the TransactionInfo to the thread, even if we didn't create
        // a new transaction here. This guarantees that the TransactionInfo stack
        // will be managed correctly even if no transaction was created by this aspect.
        txInfo.bindToThread();
        return txInfo;
    }

总结

本章详细介绍了TransactionStatus如何生成,TransactionInfo如何生成。大家应该了解基本的对象关系,TransactionInfo, TransactionStatus, HibernateTransactionObject, SessionHolder,ConnectionHolder, session, transaction,已经目前使用的线程变量,主要是保存sessionHolder和connectionHolder的resource,还有持有transactionInfo的transactionInfoHolder

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值