spring---transaction(3)---源代码分析(事务的管理器PlatformTransactionManager)

写在前面

  由于实现事务功能的方式各不相同,Spring进行了统一的抽象,形成了PlatformTransactionManager事务管理器顶级接口(平台事务管理器),事务的提交、回滚等操作全部交给它来实现

  先来看下三大接口

    • PlatformTransactionManager : 事务管理器

    • TransactionDefinition : 事务的一些基础信息,如超时时间、隔离级别、传播属性等

    • TransactionStatus : 事务的一些状态信息,如是否是一个新的事务、是否已被标记为回滚

  一般我们给事务管理器的默认实现为DataSourceTransactionManager

    <!-- 事务管理器配置 -->
    <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource" />
    </bean>

 

DataSourceTransactionManager(事务管理器接口定义PlatformTransactionManager)

PlatformTransactionManager

  • AbstractPlatformTransactionManager
    •   DataSourceTransactionManager(重点)
    •   HibernateTransactionManager
    •   JpaTransactionManager
public interface PlatformTransactionManager {
    //获取一个具体的事务状态信息
    TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException;
    //提交一个事务状态信息
    void commit(TransactionStatus status) throws TransactionException;
    //回滚一个事务状态信息
    void rollback(TransactionStatus status) throws TransactionException;
}

 

 

获取Object transaction:

  大体内容就是先获取上述说明(TransactionStatus)的Object transaction,判断当前事务是否已存在,如果存在则进行事务的传播属性处理,后面详细说明,如果不存在new DefaultTransactionStatus,新创建一个事务,同时使用Object transaction开启事务。 分成了几个过程:

  

  1. 获取Object transaction:不同的事务管理器获取不同的Object transaction

  DataSourceTransactionManager就是获取上述的DataSourceTransactionObject

  从当前线程中获取绑定的ConnectionHolder,可能为null,如果为null,则会在下一个开启事务的过程中,从dataSource中获取一个Connection,封装成ConnectionHolder,然后再绑定到当前线程

然后我们new 一个DataSourceTransactionObject了,具体过程如下:

    @Override
    protected Object doGetTransaction() {
        DataSourceTransactionObject txObject = new DataSourceTransactionObject();
        txObject.setSavepointAllowed(isNestedTransactionAllowed());
        ConnectionHolder conHolder =
                (ConnectionHolder) TransactionSynchronizationManager.getResource(this.dataSource);
        txObject.setConnectionHolder(conHolder, false);
        return txObject;
    }

 

  HibernateTransactionManager获取HibernateTransactionObject

  从当前线程中获取绑定的SessionHolder,可能为null,如果为null,则会在下一个开启事务的过程中从sessionFactory中获取一个session,然后封装成SessionHolder,然后再绑定到当前线程

然后我们就可以new 一个HibernateTransactionObject了,具体过程如下:

    @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 [" + 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;
    }

 

  2. 构建DefaultTransactionStatus,使用Object transaction开启事务

  

  DataSourceTransactionManager的DataSourceTransactionObject开启过程如下:

  首先判断之前的获取当前线程绑定的ConnectionHolder是否为null,如果为null,从dataSource中获取一个Connection,封装成ConnectionHolder,然后再绑定到当前线程因为开启了一个事务,则必须要关闭DataSourceTransactionObject中Connection的自动提交

    @Override
    protected void doBegin(Object transaction, TransactionDefinition definition) {
        DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
        Connection con = null;

        try {
            if (txObject.getConnectionHolder() == null ||
                    txObject.getConnectionHolder().isSynchronizedWithTransaction()) {
                Connection newCon = this.dataSource.getConnection();
                if (logger.isDebugEnabled()) {
                    logger.debug("Acquired Connection [" + newCon + "] for JDBC transaction");
                }
                txObject.setConnectionHolder(new ConnectionHolder(newCon), true);
            }

            txObject.getConnectionHolder().setSynchronizedWithTransaction(true);
            con = txObject.getConnectionHolder().getConnection();

            Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);
            txObject.setPreviousIsolationLevel(previousIsolationLevel);

            // Switch to manual commit if necessary. This is very expensive in some JDBC drivers,
            // so we don't want to do it unnecessarily (for example if we've explicitly
            // configured the connection pool to set it already).
            if (con.getAutoCommit()) {
                txObject.setMustRestoreAutoCommit(true);
                if (logger.isDebugEnabled()) {
                    logger.debug("Switching JDBC Connection [" + con + "] to manual commit");
                }
                con.setAutoCommit(false);
            }
            txObject.getConnectionHolder().setTransactionActive(true);

            int timeout = determineTimeout(definition);
            if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {
                txObject.getConnectionHolder().setTimeoutInSeconds(timeout);
            }

            // Bind the session holder to the thread.
            if (txObject.isNewConnectionHolder()) {
                TransactionSynchronizationManager.bindResource(getDataSource(), txObject.getConnectionHolder());
            }
        }

        catch (Throwable ex) {
            if (txObject.isNewConnectionHolder()) {
                DataSourceUtils.releaseConnection(con, this.dataSource);
                txObject.setConnectionHolder(null, false);
            }
            throw new CannotCreateTransactionException("Could not open JDBC Connection for transaction", ex);
        }
    }

 

  HibernateTransactionManager的HibernateTransactionObject开启过程如下:

也是同样的逻辑,如果SessionHolder为null,则从SessionFactory中获取一个Session,然后封装成SessionHolder,然后把这个SessionHolder绑定到当前线程

 

  3. 第二个接口:void rollback(TransactionStatus status) 回滚事务

  回滚,则还是利用DefaultTransactionStatus内部的Object transaction来执行回滚操作

  DataSourceTransactionManager就是使用DataSourceTransactionObject中的Connection来进行回滚操作

    @Override
    protected void doRollback(DefaultTransactionStatus status) {
        DataSourceTransactionObject txObject = (DataSourceTransactionObject) status.getTransaction();
        Connection con = txObject.getConnectionHolder().getConnection();
        if (status.isDebug()) {
            logger.debug("Rolling back JDBC transaction on Connection [" + con + "]");
        }
        try {
            con.rollback();
        }
        catch (SQLException ex) {
            throw new TransactionSystemException("Could not roll back JDBC transaction", ex);
        }
    }

  

  HibernateTransactionManager就是使用HibernateTransactionObject中的SessionHolder中的Session创建的事务Transaction来进行回滚操作

    @Override
    protected void doRollback(DefaultTransactionStatus status) {
        HibernateTransactionObject txObject = (HibernateTransactionObject) status.getTransaction();
        if (status.isDebug()) {
            logger.debug("Rolling back Hibernate transaction on Session [" +
                    txObject.getSessionHolder().getSession() + "]");
        }
        try {
            txObject.getSessionHolder().getTransaction().rollback();
        }
        catch (org.hibernate.TransactionException ex) {
            throw new TransactionSystemException("Could not roll back Hibernate transaction", ex);
        }
        catch (HibernateException ex) {
            // Shouldn't really happen, as a rollback doesn't cause a flush.
            throw convertHibernateAccessException(ex);
        }
        finally {
            if (!txObject.isNewSession() && !this.hibernateManagedSession) {
                // Clear all pending inserts/updates/deletes in the Session.
                // Necessary for pre-bound Sessions, to avoid inconsistent state.
                txObject.getSessionHolder().getSession().clear();
            }
        }
    }

 

  4.第三个接口: void commit(TransactionStatus status) 提交事务

  同理,DataSourceTransactionManager依托内部的Connection来完成提交操作

  HibernateTransactionManager依托内部的Transaction来完成提交操作

posted @ 2017-04-25 09:14  qtyy  阅读(1542)  评论(0编辑  收藏  举报