TransactionSynchronizationManager使用ThreadLocal机制为每个线程保存其自己的事务信息,包括数据库连接资源、事务同步回调、当前事务名称、只读状态、隔离级别等。这样,每个线程都可以拥有自己独立的数据副本,不同线程之间的数据不会互相干扰,保证了事务的隔离性和安全性。
事务同步管理器同时提供了一个接口TransactionSynchronization作为扩展点,通常情况下只需继承抽象适配类TransactionSynchronizationAdapter完成扩展。扩展点主要是在事务提交之前增加了扩展,方便用户控制事务提交前后的行为。
具体实现过程可以参考SqlSessionSynchronization、ConnectionSynchronization。
事务同步管理器提供了全局绑定资源、解绑资源、获取资源的静态方法。 其中资源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,即SqlSessionSynchronization & ConnectionSynchronization。
事务中的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。