Spring原理【9】Spring组件实现篇(二)

148 阅读5分钟

Spring事务处理器的设计与实现

Spring事务处理的应用场景

下面,我们以DataSourceTransactionManager和HibernateTransactionManager这两个常用的事务处理器为例,探讨一下在具体的事务处理器中如何实现事务创建、提交和回滚这些底层的事务处理操作。在DataSourceTransationManager和HibernateTransationManager的设计中,如下图所示,它们作为具体的事务管理器实现,和其他事务管理器实现一样,比如JtaTransactionManager,JpaTransactionManager和JdoTransactionManager,继承自AbstractPlatformManager、作为一个基类,AbstractPlatfromManager封装了Spring事务处理中通用的处理部分,比如事务的创建、提交、回滚,事务状态和信息的处理,与线程的绑定等,有了这些通用处理的支持,对于具体的事务管理器而言,它们只需要处理和具体数据源相关的组件设置就可以了,比如在HibernateTransactionManager中,就只需要配置好和Hibnernate事务处理相关的接口以及相关的设置。所以,从这个类设计关系上,我们也可以看到,Spring事务处理的主要过程是分两个部分完成的,通用的事务处理框架是在AbstractPlatformManager中完成,而Spring的事务接口与数据源实现的接口,多半是由具体的事务管理器来完成,它们都是作为AbstractPlatformManager的子类来是使用的。 我们可以看到,在PlatformTransactionManager的设计中,通过PlatformTransactionManager设计了一系列与事务处理息息相关的接口方法,如getTransaction、commit、rollback这些和事务处理相关的统一接口。对于这些接口的实现,很大一部分是由AbstractTransactionManager来完成的,这个类中的doGetTransaction、doCommit等方法和PlatformTransactionManager的方法对应,实现的是事务处理中相对通用的部分。在这个AbstractPlatformManager下,为具体的数据源配置了不同的事务处理器,以处理不同数据源的事务处理,从而形成了一个从抽象到具体的事务处理中间平台设计,使应用通过声明式事务处理,即开即用事务处理服务,隔离那些与特定的数据源相关的具体实现。

image-20240108101144715.png

DataSourceTransactionManager的实现

我们先看一下DataSourceTransactionManager,在这个事务处理器中,它的实现直接与事务处理的底层实现相关,具体的实现时序如下图所示。在DataSourceTransactionManager中,在事务开始的时候,会调用doBegin方法,首先会得到相对应的Connection,然后可以根据事务设置的需要,对Connection的相关属性进行配置,比如将Connection的autoCommit功能关闭,并对像TimeoutInSeconds这样的事务处理参数进行设置,最后通过TransactionSynchronizationManager来对资源进行绑定。 具体的实现如下代码清单所示。在如下代码清单中,我们可以看到,DataSourceTransactionManager作为AbstractPlatformTransactionManager的子类,在AbstractPlatformTransactionManager中已经为事务实现设计好了一系列的模板方法,比如事务提交、回滚处理等。在DataSourceTransactionManager中,可以看到对模板方法中一些抽象方法的具体实现。例如,由DataSourceTransactionManager的doBegin方法实现负责事务的创建工作。具体来说,如果使用DataSource创建事务,最终通过设置Connection的AutoCommit属性来对事务处理进行配置。在实现过程中,需要把数据库的Connection和当前的线程进行绑定。对于事务的提交和回滚,都是通过直接调用Connection的提交和回滚来完成的,在这个实现过程中,如何取得事务处理场景中的Connection对象,也是一个值得注意的地方。

image-20240108142408607.png

org.springframework.jdbc.datasource.DataSourceTransactionManager的实现如下:

public class DataSourceTransactionManager extends AbstractPlatformTransactionManager
       implements ResourceTransactionManager, InitializingBean {
    // 注入的DataSource
    @Nullable
    private DataSource dataSource;
​
    private boolean enforceReadOnly = false;
    
    // 这里是产生Transaction的地方,为Transaction的创建提供服务
    // 对数据库而言,事务工作时由Connection来完成的,此处通过ConnectionHolder进行管理,封装到DataSourceTransactionObject对象中,在这个封装过程中增加了许多为事务处理服务的控制数据
    @Override
    protected Object doGetTransaction() {
       DataSourceTransactionObject txObject = new DataSourceTransactionObject();
       txObject.setSavepointAllowed(isNestedTransactionAllowed());
       // 获取与当前线程绑定的数据库Connection,这个Connection在第一个事务开始的地方与线程绑定
       ConnectionHolder conHolder =
             (ConnectionHolder) TransactionSynchronizationManager.getResource(obtainDataSource());
       txObject.setConnectionHolder(conHolder, false);
       return txObject;
    }
​
    // 这里是判断是否已经存在事务的地方,由ConnectionHolder的isTransactionActive属性来控制
    @Override
    protected boolean isExistingTransaction(Object transaction) {
       DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
       return (txObject.hasConnectionHolder() && txObject.getConnectionHolder().isTransactionActive());
    }
​
    // 这里是事务开始的地方
    @Override
    protected void doBegin(Object transaction, TransactionDefinition definition) {
       DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
       Connection con = null;
​
       try {
          if (!txObject.hasConnectionHolder() ||
                txObject.getConnectionHolder().isSynchronizedWithTransaction()) {
             Connection newCon = obtainDataSource().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);
          txObject.setReadOnly(definition.isReadOnly());
​
          // 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);
          }
​
          prepareTransactionalConnection(con, definition);
          txObject.getConnectionHolder().setTransactionActive(true);
​
          int timeout = determineTimeout(definition);
          if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {
             txObject.getConnectionHolder().setTimeoutInSeconds(timeout);
          }
​
          // Bind the connection holder to the thread. 把当前的数据库Connection和线程绑定
          if (txObject.isNewConnectionHolder()) {
             TransactionSynchronizationManager.bindResource(obtainDataSource(), txObject.getConnectionHolder());
          }
       }
​
       catch (Throwable ex) {
          if (txObject.isNewConnectionHolder()) {
             DataSourceUtils.releaseConnection(con, obtainDataSource());
             txObject.setConnectionHolder(null, false);
          }
          throw new CannotCreateTransactionException("Could not open JDBC Connection for transaction", ex);
       }
    }
​
    @Override
    protected Object doSuspend(Object transaction) {
       DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
       txObject.setConnectionHolder(null);
       return TransactionSynchronizationManager.unbindResource(obtainDataSource());
    }
​
    @Override
    protected void doResume(@Nullable Object transaction, Object suspendedResources) {
       TransactionSynchronizationManager.bindResource(obtainDataSource(), suspendedResources);
    }
​
    // 事务的提交过程
    @Override
    protected void doCommit(DefaultTransactionStatus status) {
       // 取得Connection以后,通过Connection进行提交
       DataSourceTransactionObject txObject = (DataSourceTransactionObject) status.getTransaction();
       Connection con = txObject.getConnectionHolder().getConnection();
       if (status.isDebug()) {
          logger.debug("Committing JDBC transaction on Connection [" + con + "]");
       }
       try {
          con.commit();
       }
       catch (SQLException ex) {
          throw translateException("JDBC commit", ex);
       }
    }
    // 事务的回滚过程,使用Connection的rollback方法
    @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 translateException("JDBC rollback", ex);
       }
    }
​
    @Override
    protected void doSetRollbackOnly(DefaultTransactionStatus status) {
       DataSourceTransactionObject txObject = (DataSourceTransactionObject) status.getTransaction();
       if (status.isDebug()) {
          logger.debug("Setting JDBC transaction [" + txObject.getConnectionHolder().getConnection() +
                "] rollback-only");
       }
       txObject.setRollbackOnly();
    }
​
    @Override
    protected void doCleanupAfterCompletion(Object transaction) {
       DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
​
       // Remove the connection holder from the thread, if exposed.
       if (txObject.isNewConnectionHolder()) {
          TransactionSynchronizationManager.unbindResource(obtainDataSource());
       }
​
       // Reset connection.
       Connection con = txObject.getConnectionHolder().getConnection();
       try {
          if (txObject.isMustRestoreAutoCommit()) {
             con.setAutoCommit(true);
          }
          DataSourceUtils.resetConnectionAfterTransaction(
                con, txObject.getPreviousIsolationLevel(), txObject.isReadOnly());
       }
       catch (Throwable ex) {
          logger.debug("Could not reset JDBC Connection after transaction", ex);
       }
​
       if (txObject.isNewConnectionHolder()) {
          if (logger.isDebugEnabled()) {
             logger.debug("Releasing JDBC Connection [" + con + "] after transaction");
          }
          DataSourceUtils.releaseConnection(con, this.dataSource);
       }
​
       txObject.getConnectionHolder().clear();
    }
​
    protected void prepareTransactionalConnection(Connection con, TransactionDefinition definition)
          throws SQLException {
​
       if (isEnforceReadOnly() && definition.isReadOnly()) {
          try (Statement stmt = con.createStatement()) {
             stmt.executeUpdate("SET TRANSACTION READ ONLY");
          }
       }
    }
​
    protected RuntimeException translateException(String task, SQLException ex) {
       return new TransactionSystemException(task + " failed", ex);
    }
​
}

上面介绍了使用DataSourceTransactionManager实现事务创建、提交和回滚的过程,基本上与单独使用Connection实现事务处理是一样的,也是通过设置autoCommit属性,调用Connection的commit和rollback方法来完成的。看到这里,大家一定会觉得非常的熟悉。而我们在声明式事务处理中看到的那些事务处理属性,并不在DataSourceTransactionManager中完成,这和我们在前面分析中看到的是一致的。