事务同步管理器TransactionSynchronizationManager

TransactionSynchronizationManager使用ThreadLocal机制为每个线程保存其自己的事务信息,包括数据库连接资源、事务同步回调、当前事务名称、只读状态、隔离级别等。这样,每个线程都可以拥有自己独立的数据副本,不同线程之间的数据不会互相干扰,保证了事务的隔离性和安全性。

事务同步管理器同时提供了一个接口TransactionSynchronization作为扩展点,通常情况下只需继承抽象适配类TransactionSynchronizationAdapter完成扩展。扩展点主要是在事务提交之前增加了扩展,方便用户控制事务提交前后的行为。

具体实现过程可以参考SqlSessionSynchronizationConnectionSynchronization

事务同步管理器提供了全局绑定资源、解绑资源、获取资源的静态方法。 其中资源resources主要是指本地线程集合类型的元素:key通常为DataSource or SqlSession、value即为ConnectionHolder or SqlSessionHolder。

public abstract class TransactionSynchronizationManager {

	ThreadLocal<Map<Object, Object>> resources = new NamedThreadLocal<>("Transactional resources");
	ThreadLocal<Set<TransactionSynchronization>> synchronizations = new NamedThreadLocal<>("Transaction synchronizations");
	
	public static Object getResource(Object key) {
		// key通常是指dataSource
		Object actualKey = TransactionSynchronizationUtils.unwrapResourceIfNecessary(key);
		//从本地线程resources尝试获取ConnectionHolder,不存在则返回null
		Object value = doGetResource(actualKey);
		return value;
	}
	public static void bindResource(Object key, Object value) throws IllegalStateException {
		Object actualKey = TransactionSynchronizationUtils.unwrapResourceIfNecessary(key);
		Map<Object, Object> map = resources.get();
		if (map == null) {
			map = new HashMap<>();
			resources.set(map);
		}
		Object oldValue = map.put(actualKey, value);
	}
}

绑定资源:【DataSource & ConnectionHolder || SqlSession & SqlSessionHolder】以kv形式作为本地线程ThreadLocal元素。

获取资源:从ThreadLocal中获取Map类型的集合元素,然后通过key 为 DataSource || SqlSession获取其value,即ConnectionHolder or SqlSessionHolder,最后从ConnectionHolder or SqlSessionHolder获取Connection or SqlSession,否则最终返回null。

解绑资源:从本地线程变量ThreadLocal中删除掉跟当前线程相关的资源信息。

注意:先SqlSession后Connection;没有事务的前提下每次jdbc操作数据库时SqlSession、Connection都是新建,更不会与本地线程建立任何关系。


1.SqlSession & Connection

SqlSession & Connection这两种资源对应的xxxHolder在与线程建立绑定关系的前提是:TransactionSynchronization必须处于激活状态。

不管事务存在与否,都是通过SqlSessionUtils创建SqlSession,DataSourceUtils创建Connection。

1.1.SqlSession

public final class SqlSessionUtils {

    public static SqlSession getSqlSession(SqlSessionFactory sessionFactory, ExecutorType executorType,PersistenceExceptionTranslator exceptionTranslator) {
        // 尝试从 事务同步管理器本地线程属性resources 获取SqlSession
        SqlSessionHolder holder = (SqlSessionHolder) TransactionSynchronizationManager.getResource(sessionFactory);
        // 如果 holder 不为空,则尝试从 holder 直接获取SqlSession
        SqlSession session = sessionHolder(executorType, holder);
        if (session != null) {
            return session;
        }
        // 通过 SqlSessionFactory工厂类 创建新的 SqlSession
        session = sessionFactory.openSession(executorType);
        // 尝试将 新得到的SqlSession 与 事务同步管理器 建立绑定关系
        registerSessionHolder(sessionFactory, executorType, exceptionTranslator, session);
        return session;
    }

    private static SqlSession sessionHolder(ExecutorType executorType, SqlSessionHolder holder) {
        SqlSession session = null;
        // 如果 holder 不为空,并且 SqlSession 是跟事务相关的
        if (holder != null && holder.isSynchronizedWithTransaction()) {
            holder.requested();
            session = holder.getSqlSession();
        }
        return session;
    }

    private static void registerSessionHolder(SqlSessionFactory sf, ExecutorType ct,PersistenceExceptionTranslator et, SqlSession session) {
        SqlSessionHolder holder;
        // 首先同步器必须处于激活状态
        if (TransactionSynchronizationManager.isSynchronizationActive()) {
            Environment environment = sf.getConfiguration().getEnvironment();
            // 必须是事务管理器,好像默认都是 SpringManagedTransactionFactory
            if (environment.getTransactionFactory() instanceof SpringManagedTransactionFactory) {
              holder = new SqlSessionHolder(session, ct, et);
              // 真正建立 资源与线程 的绑定关系
              TransactionSynchronizationManager.bindResource(sf, holder);
              TransactionSynchronizationManager.registerSynchronization(new SqlSessionSynchronization(holder, sf));
              // 设置 SqlSessionHolder 的属性SynchronizedWithTransaction 为true
              holder.setSynchronizedWithTransaction(true);
              holder.requested();
          } 
        } 
    }
}

1.2.Connection的获取

不管应用中是否涉及事务,数据库连接的创建都是通过DataSourceUtils工具类完成的。

public abstract class DataSourceUtils {
	
	public static Connection getConnection(DataSource dataSource) throws CannotGetJdbcConnectionException {
		return doGetConnection(dataSource);
	}

	public static Connection doGetConnection(DataSource dataSource) throws SQLException {

		ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager.getResource(dataSource);
		if (conHolder != null && (conHolder.hasConnection() || conHolder.isSynchronizedWithTransaction())) {
			conHolder.requested();
			if (!conHolder.hasConnection()) {
				conHolder.setConnection(fetchConnection(dataSource));
			}
			return conHolder.getConnection();
		}
		// 通过 DataSource 创建新的Connection
		Connection con = fetchConnection(dataSource);
		if (TransactionSynchronizationManager.isSynchronizationActive()) {
			ConnectionHolder holderToUse = conHolder;
			if (holderToUse == null) {// 创建 ConnectionHolder
				holderToUse = new ConnectionHolder(con);
			}else {
				holderToUse.setConnection(con);
			}
			holderToUse.requested();
			// 初始化TransactionSynchronization之ConnectionSynchronization
			TransactionSynchronizationManager.registerSynchronization(new ConnectionSynchronization(holderToUse, dataSource));
			holderToUse.setSynchronizedWithTransaction(true);
			if (holderToUse != conHolder) {
				// 将 Connection 与当前线程建立绑定关系
				TransactionSynchronizationManager.bindResource(dataSource, holderToUse);
			}
		}
		return con;
	}
}

优先从ThreadLocal中获取与当前线程的绑定的资源;如果不存在则通过dataSource重新新建Connection;如果此时当前线程对应的事务处于激活active状态则新建ConnectionHolder,并持有新建的Connection,最终被ThreadLocal持有 dataSource & ConnectionHolder对应的Map集合元素。


2.TransactionSynchronization

TransactionSynchronization在Spring框架中的作用主要是管理事务同步操作,确保在事务的不同阶段执行相应的回调操作‌。

事务同步操作‌:TransactionSynchronization提供了几个关键的回调方法,这些方法在事务的不同阶段被调用:

  • beforeCommit‌:在事务提交之前调用。
  • beforeCompletion‌:在事务完成之前调用。
  • commit:connection提交或者回滚。
  • afterCommit‌:在事务提交之后调用。
  • afterCompletion‌:在事务完成之后调用‌。

管理事务状态‌:TransactionSynchronizationManager帮助跟踪当前事务的状态,包括事务是否已经开启、是否处于激活状态等。它提供了静态方法来管理事务的状态,确保在多线程环境下的事务状态可以被正确管理‌。

资源访问支持‌:TransactionSynchronizationManager允许开发者存储和访问在事务生命周期内需要共享的资源。通过TransactionSynchronizationManager,开发者可以在不同的事务阶段访问并操作共享资源,确保资源的一致性和可靠性‌。

与不同事务管理机制的集成‌:TransactionSynchronizationManager不依赖于特定的事务管理机制,可以与不同的事务管理实现(如JDBC、Hibernate、JPA等)结合使用。它提供了统一的接口和管理机制,使得不同的事务管理机制可以更容易地集成和使用‌。

SqlSession & Connection存在各自的TransactionSynchronization,即SqlSessionSynchronizationConnectionSynchronization

事务中的SqlSession & Connection资源可以通过TransactionSynchronization阶段性控制操作。当资源正式托管于TransactionSynchronizationManager时其对应的TransactionSynchronization必须处于激活状态。

public abstract class TransactionSynchronizationManager {
	ThreadLocal<Set<TransactionSynchronization>> synchronizations = new NamedThreadLocal<>("Transaction synchronizations");

	public static void registerSynchronization(TransactionSynchronization synchronization){
		Set<TransactionSynchronization> synchs = synchronizations.get();
		if (synchs == null) {
			throw new IllegalStateException("Transaction synchronization is not active");
		}
		synchs.add(synchronization);
	}
    //synchronizations属性的初始化
	public static void initSynchronization() throws IllegalStateException {
		if (isSynchronizationActive()) {
			throw new IllegalStateException("Cannot activate transaction synchronization - already active");
		}
		synchronizations.set(new LinkedHashSet<>());
	}
	public static boolean isSynchronizationActive() {
		return (synchronizations.get() != null);
	}
}

TransactionSynchronization激活条件即为:成员变量synchronizations不为空。所以事务中任何资源在托管之前必须提前初始化Synchronization ~ initSynchronization。


2.1.ConnectionSynchronization

public abstract class DataSourceUtils {

	private static class ConnectionSynchronization extends TransactionSynchronizationAdapter {
		private final ConnectionHolder connectionHolder;
		private final DataSource dataSource;
		private boolean holderActive = true;

		public ConnectionSynchronization(ConnectionHolder connectionHolder, DataSource dataSource) {
			this.connectionHolder = connectionHolder;
			this.dataSource = dataSource;
		}

		@Override
		public void suspend() {
			if (this.holderActive) {
				TransactionSynchronizationManager.unbindResource(this.dataSource);
				if (this.connectionHolder.hasConnection() && !this.connectionHolder.isOpen()) {
					releaseConnection(this.connectionHolder.getConnection(), this.dataSource);
					this.connectionHolder.setConnection(null);
				}
			}
		}

		@Override
		public void resume() {
			if (this.holderActive) {
				TransactionSynchronizationManager.bindResource(this.dataSource, this.connectionHolder);
			}
		}

		@Override
		public void beforeCompletion() {
			if (!this.connectionHolder.isOpen()) {
				
				TransactionSynchronizationManager.unbindResource(this.dataSource);
				this.holderActive = false;
				if (this.connectionHolder.hasConnection()) {
					releaseConnection(this.connectionHolder.getConnection(), this.dataSource);
				}
			}
		}

		@Override
		public void afterCompletion(int status) {
			if (this.holderActive) {
				TransactionSynchronizationManager.unbindResourceIfPossible(this.dataSource);
				this.holderActive = false;
				if (this.connectionHolder.hasConnection()) {
					releaseConnection(this.connectionHolder.getConnection(), this.dataSource);
					this.connectionHolder.setConnection(null);
				}
			}
			this.connectionHolder.reset();
		}
	}

}

2.2.SqlSessionSynchronization

public final class SqlSessionUtils {

    private static final class SqlSessionSynchronization extends TransactionSynchronizationAdapter {
      private final SqlSessionHolder holder;
      private final SqlSessionFactory sessionFactory;
      private boolean holderActive = true;

      public SqlSessionSynchronization(SqlSessionHolder holder, SqlSessionFactory sessionFactory) {
          this.holder = holder;
          this.sessionFactory = sessionFactory;
      }
      @Override
      public void suspend() {
          if (this.holderActive) {
              TransactionSynchronizationManager.unbindResource(this.sessionFactory);
          }
      }
      @Override
      public void resume() {
          if (this.holderActive) {
              TransactionSynchronizationManager.bindResource(this.sessionFactory, this.holder);
          }
      }

      @Override
      public void beforeCommit(boolean readOnly) {
          if (TransactionSynchronizationManager.isActualTransactionActive()) {
              this.holder.getSqlSession().commit();
          }
      }
      @Override
      public void beforeCompletion() {
          if (!this.holder.isOpen()) {
              TransactionSynchronizationManager.unbindResource(sessionFactory);
              this.holderActive = false;
              this.holder.getSqlSession().close();
          }
      }

      @Override
      public void afterCompletion(int status) {
          if (this.holderActive) {
              TransactionSynchronizationManager.unbindResourceIfPossible(sessionFactory);
              this.holderActive = false;
              this.holder.getSqlSession().close();
          }
          this.holder.reset();
      }
    }
}

3.DataSourceTransactionManager

public class DataSourceTransactionManagerAutoConfiguration {
  @Configuration(proxyBeanMethods = false)
  @ConditionalOnSingleCandidate(DataSource.class)
  static class DataSourceTransactionManagerConfiguration {

    @Bean
    @ConditionalOnMissingBean(PlatformTransactionManager.class)
    DataSourceTransactionManager transactionManager(DataSource dataSource,
        ObjectProvider<TransactionManagerCustomizers> transactionManagerCustomizers) {
      DataSourceTransactionManager transactionManager = new DataSourceTransactionManager(dataSource);
      transactionManagerCustomizers.ifAvailable((customizers) -> customizers.customize(transactionManager));
      return transactionManager;
    }

  }
}

DataSourceTransactionManager继承AbstractPlatformTransactionManager实现接口PlatformTransactionManager。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值