part5-transaction-synchronization-manager
约 3308 字大约 11 分钟
2026-05-24
系列文章:《深入Spring事务与数据源:从注解到数据库连接的全链路解析》
第五篇:TransactionSynchronizationManager的ThreadLocal机制
基于版本:Spring Framework 5.3.x
前置阅读:第四篇:JDBC事务的实现
前言
在前面四篇文章中,我们反复提到一个核心组件:TransactionSynchronizationManager。它是Spring事务管理的"中枢神经",负责:
- 管理线程绑定的资源(如数据库连接)
- 维护事务同步回调
- 存储事务上下文信息
// 绑定资源
TransactionSynchronizationManager.bindResource(dataSource, connectionHolder);
// 获取资源
ConnectionHolder conHolder = (ConnectionHolder)
TransactionSynchronizationManager.getResource(dataSource);
// 注册同步回调
TransactionSynchronizationManager.registerSynchronization(synchronization);本文将深入分析TransactionSynchronizationManager的ThreadLocal机制,揭示它是如何实现线程安全的事务管理的。
一、TransactionSynchronizationManager的架构设计
1.1 核心职责
TransactionSynchronizationManager是Spring事务管理的核心工具类,负责:
- 资源管理:将资源(如Connection)绑定到当前线程
- 同步管理:管理事务生命周期回调
- 事务上下文:存储事务属性(名称、隔离级别、只读标记等)
1.2 ThreadLocal的核心地位
public abstract class TransactionSynchronizationManager {
// ========== 核心ThreadLocal变量 ==========
// 1. 资源映射:数据源 → ConnectionHolder
private static final ThreadLocal<Map<Object, Object>> resources =
new NamedThreadLocal<>("Transactional resources");
// 2. 事务同步回调列表
private static final ThreadLocal<Set<TransactionSynchronization>> synchronizations =
new NamedThreadLocal<>("Transaction synchronizations");
// 3. 当前事务名称
private static final ThreadLocal<String> currentTransactionName =
new NamedThreadLocal<>("Current transaction name");
// 4. 当前事务只读标记
private static final ThreadLocal<Boolean> currentTransactionReadOnly =
new NamedThreadLocal<>("Current transaction read-only status");
// 5. 当前事务隔离级别
private static final ThreadLocal<Integer> currentTransactionIsolationLevel =
new NamedThreadLocal<>("Current transaction isolation level");
// 6. 事务是否实际活跃
private static final ThreadLocal<Boolean> actualTransactionActive =
new NamedThreadLocal<>("Actual transaction active");
}ThreadLocal的作用:
- 每个线程有独立的副本
- 线程之间完全隔离
- 确保事务的线程安全性
二、资源管理机制
2.1 bindResource:绑定资源到线程
源码位置:spring-tx/src/main/java/org/springframework/transaction/support/TransactionSynchronizationManager.java
public static void bindResource(Object key, Object value) throws IllegalStateException {
// 1. 获取key对应的资源
Object actualKey = TransactionSynchronizationUtils.unwrapResourceIfNecessary(key);
// 2. 获取当前线程的资源Map
Map<Object, Object> map = resources.get();
// 3. 如果Map不存在,创建新的
if (map == null) {
map = new HashMap<>();
resources.set(map);
}
// 4. 如果资源已存在,抛异常(避免覆盖)
Object oldValue = map.put(actualKey, value);
if (oldValue != null) {
throw new IllegalStateException("Already value [" + oldValue + "] for key [" +
actualKey + "] bound to thread");
}
if (logger.isTraceEnabled()) {
logger.trace("Bound value [" + value + "] for key [" + actualKey + "] to thread");
}
}关键点:
- key通常是DataSource:用于区分不同数据源
- value是ConnectionHolder:封装的数据库连接
- resources是
ThreadLocal<Map>:每个线程有自己的资源Map - 一个线程可以绑定多个数据源:支持多数据源事务
2.2 getResource:从线程获取资源
public static Object getResource(Object key) {
// 1. 解包装key
Object actualKey = TransactionSynchronizationUtils.unwrapResourceIfNecessary(key);
// 2. 获取当前线程的资源Map
Map<Object, Object> map = resources.get();
// 3. 如果Map为空,返回null
if (map == null) {
return null;
}
// 4. 从Map中获取资源
Object value = map.get(actualKey);
if (logger.isTraceEnabled()) {
logger.trace("Retrieved value [" + value + "] for key [" + actualKey + "] bound to thread");
}
return value;
}使用场景:
// DataSourceTransactionManager.doGetTransaction
ConnectionHolder conHolder =
(ConnectionHolder) TransactionSynchronizationManager.getResource(dataSource);
if (conHolder != null) {
// 已存在事务
} else {
// 还没有事务
}2.3 unbindResource:从线程解绑资源
public static Object unbindResource(Object key) throws IllegalStateException {
Object actualKey = TransactionSynchronizationUtils.unwrapResourceIfNecessary(key);
// 获取资源
Object value = doUnbindResource(actualKey);
if (value == null) {
throw new IllegalStateException("No value for key [" + actualKey +
"] bound to thread");
}
return value;
}
private static Object doUnbindResource(Object actualKey) {
Map<Object, Object> map = resources.get();
if (map == null) {
return null;
}
Object value = map.remove(actualKey);
// 如果Map为空,清理ThreadLocal
if (map.isEmpty()) {
resources.remove();
if (logger.isTraceEnabled()) {
logger.trace("Removed thread-local transaction resource map");
}
}
return value;
}关键点:
- 从Map中移除资源
- 如果Map为空,调用
resources.remove()清理ThreadLocal - 防止内存泄漏
2.4 unbindIfPossible:尝试解绑(不抛异常)
@Nullable
public static Object unbindResourceIfPossible(Object key) {
Object actualKey = TransactionSynchronizationUtils.unwrapResourceIfNecessary(key);
return doUnbindResource(actualKey);
}使用场景:事务清理时,不确定资源是否存在
// 安全地解绑,不存在也不抛异常
Object value = TransactionSynchronizationManager.unbindResourceIfPossible(dataSource);三、资源绑定的完整示例
3.1 单数据源场景
// 事务开始
doBegin() {
// 获取连接
Connection conn = dataSource.getConnection();
ConnectionHolder holder = new ConnectionHolder(conn);
// 绑定到ThreadLocal
TransactionSynchronizationManager.bindResource(dataSource, holder);
}
// 执行业务
jdbcTemplate.update(...) {
// 获取连接
ConnectionHolder holder = (ConnectionHolder)
TransactionSynchronizationManager.getResource(dataSource);
Connection conn = holder.getConnection();
// 使用conn执行SQL
}
// 事务提交
doCleanupAfterCompletion() {
// 解绑资源
TransactionSynchronizationManager.unbindResource(dataSource);
}ThreadLocal的变化:
事务开始前:
resources ThreadLocal: null
doBegin后:
resources ThreadLocal: {
DruidDataSource@123 → ConnectionHolder@456
}
业务执行中:
resources ThreadLocal: {
DruidDataSource@123 → ConnectionHolder@456
}
事务清理后:
resources ThreadLocal: null (已清理)3.2 多数据源场景
@Configuration
public class DataSourceConfig {
@Bean
@Primary
public DataSource primaryDataSource() {
return new DruidDataSource();
}
@Bean
public DataSource secondaryDataSource() {
return new DruidDataSource();
}
}
// 嵌套事务,使用不同数据源
@Transactional
public void method() {
// 使用主数据源
jdbcTemplatePrimary.update(...);
methodSecondary();
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void methodSecondary() {
// 使用副数据源
jdbcTemplateSecondary.update(...);
}ThreadLocal的变化:
外层事务开始:
resources: {
PrimaryDataSource → ConnectionHolder1
}
内层事务开始(suspend):
挂起PrimaryDataSource的连接
resources: {
PrimaryDataSource → ConnectionHolder1 (保存但不活跃)
}
获取SecondaryDataSource的连接
resources: {
PrimaryDataSource → ConnectionHolder1,
SecondaryDataSource → ConnectionHolder2
}
内层事务结束:
释放SecondaryDataSource的连接
resources: {
PrimaryDataSource → ConnectionHolder1
}
外层事务结束:
释放PrimaryDataSource的连接
resources: null四、事务同步机制
4.1 initSynchronization:初始化同步
public static void initSynchronization() throws IllegalStateException {
if (isSynchronizationActive()) {
throw new IllegalStateException("Cannot activate transaction synchronization - already active");
}
// 创建LinkedHashSet(保证顺序)
synchronizations.set(new LinkedHashSet<>());
if (logger.isTraceEnabled()) {
logger.trace("Initialized transaction synchronization");
}
}调用时机:事务开始时
// AbstractPlatformTransactionManager
private TransactionStatus startTransaction(...) {
// 创建事务状态
DefaultTransactionStatus status = newTransactionStatus(...);
// 开启事务
doBegin(transaction, definition);
// 初始化同步
prepareSynchronization(status, definition);
return status;
}
protected void prepareSynchronization(DefaultTransactionStatus status,
TransactionDefinition definition) {
if (status.isNewSynchronization()) {
TransactionSynchronizationManager.setActualTransactionActive(true);
TransactionSynchronizationManager.setCurrentTransactionName(
definition.getName());
TransactionSynchronizationManager.setCurrentTransactionIsolationLevel(
definition.getIsolationLevel());
TransactionSynchronizationManager.setCurrentTransactionReadOnly(
definition.isReadOnly());
// 初始化同步回调列表
TransactionSynchronizationManager.initSynchronization();
}
}4.2 registerSynchronization:注册同步回调
public static void registerTransactionSynchronization(
TransactionSynchronization synchronization) throws IllegalStateException {
Set<TransactionSynchronization> synchs = synchronizations.get();
if (synchs == null) {
throw new IllegalStateException(
"Transaction synchronization is not active");
}
synchs.add(synchronization);
}使用场景:MyBatis注册SqlSession同步
// MyBatis的SqlSessionUtils
public static void registerSessionHolder(SqlSessionFactory sessionFactory,
ExecutorType executorType, PersistenceExceptionTranslator exceptionTranslator,
SqlSession session) {
SqlSessionHolder holder = new SqlSessionHolder(session);
// 绑定到ThreadLocal
TransactionSynchronizationManager.bindResource(sessionFactory, holder);
// 注册同步回调
TransactionSynchronizationManager.registerSynchronization(
new SqlSessionSynchronization(holder, sessionFactory));
}4.3 TransactionSynchronization接口
public interface TransactionSynchronization extends Ordered, Flushable {
int STATUS_COMMITTED = 0;
int STATUS_ROLLED_BACK = 1;
int STATUS_UNKNOWN = 2;
// 事务挂起时调用
default void suspend() { }
// 事务恢复时调用
default void resume() { }
// 刷新资源
@Override
default void flush() { }
// 提交前调用
default void beforeCommit(boolean readOnly) { }
// 完成前调用(提交或回滚前)
default void beforeCompletion() { }
// 提交后调用
default void afterCommit() { }
// 完成后调用(提交或回滚后)
default void afterCompletion(int status) { }
}4.4 触发同步回调
beforeCommit回调
private void triggerBeforeCommit(DefaultTransactionStatus status) {
if (status.isNewSynchronization()) {
List<TransactionSynchronization> synchs =
new ArrayList<>(TransactionSynchronizationManager.getSynchronizations());
for (TransactionSynchronization synchronization : synchs) {
synchronization.beforeCommit(status.isReadOnly());
}
}
}beforeCompletion回调
private void triggerBeforeCompletion(DefaultTransactionStatus status) {
if (status.isNewSynchronization()) {
List<TransactionSynchronization> synchs =
new ArrayList<>(TransactionSynchronizationManager.getSynchronizations());
for (TransactionSynchronization synchronization : synchs) {
synchronization.beforeCompletion();
}
}
}afterCommit回调
private void triggerAfterCommit(DefaultTransactionStatus status) {
if (status.isNewSynchronization()) {
List<TransactionSynchronization> synchs =
new ArrayList<>(TransactionSynchronizationManager.getSynchronizations());
for (TransactionSynchronization synchronization : synchs) {
synchronization.afterCommit();
}
}
}afterCompletion回调
private void triggerAfterCompletion(DefaultTransactionStatus status, int status) {
if (status.isNewSynchronization()) {
List<TransactionSynchronization> synchs =
TransactionSynchronizationManager.getSynchronizations();
for (TransactionSynchronization synchronization : synchs) {
synchronization.afterCompletion(status);
}
}
}4.5 clearSynchronization:清理同步
public static void clearSynchronization() throws IllegalStateException {
if (!isSynchronizationActive()) {
throw new IllegalStateException("Transaction synchronization is not active");
}
synchronizations.remove();
if (logger.isTraceEnabled()) {
logger.trace("Cleared transaction synchronization");
}
}调用时机:事务完成后
private void cleanupAfterCompletion(DefaultTransactionStatus status) {
status.setCompleted();
if (status.isNewSynchronization()) {
// 清理同步
TransactionSynchronizationManager.clearSynchronization();
TransactionSynchronizationManager.setCurrentTransactionName(null);
TransactionSynchronizationManager.setActualTransactionActive(false);
// ...
}
}五、事务上下文管理
5.1 设置事务属性
// 设置事务名称
public static void setCurrentTransactionName(@Nullable String name) {
if (name == null) {
currentTransactionName.remove();
} else {
currentTransactionName.set(name);
}
}
// 设置只读标记
public static void setCurrentTransactionReadOnly(boolean readOnly) {
if (!readOnly) {
currentTransactionReadOnly.remove();
} else {
currentTransactionReadOnly.set(Boolean.TRUE);
}
}
// 设置隔离级别
public static void setCurrentTransactionIsolationLevel(@Nullable Integer isolationLevel) {
if (isolationLevel == null) {
currentTransactionIsolationLevel.remove();
} else {
currentTransactionIsolationLevel.set(isolationLevel);
}
}
// 设置事务活跃状态
public static void setActualTransactionActive(boolean actualTransactionActive) {
if (!actualTransactionActive) {
TransactionSynchronizationManager.actualTransactionActive.remove();
} else {
TransactionSynchronizationManager.actualTransactionActive.set(Boolean.TRUE);
}
}5.2 获取事务属性
// 获取事务名称
@Nullable
public static String getCurrentTransactionName() {
return currentTransactionName.get();
}
// 获取只读标记
public static boolean isCurrentTransactionReadOnly() {
return (currentTransactionReadOnly.get() != null);
}
// 获取隔离级别
@Nullable
public static Integer getCurrentTransactionIsolationLevel() {
return currentTransactionIsolationLevel.get();
}
// 事务是否活跃
public static boolean isActualTransactionActive() {
return (actualTransactionActive.get() != null);
}
// 同步是否激活
public static boolean isSynchronizationActive() {
return (synchronizations.get() != null);
}六、ThreadLocal的底层实现
6.1 ThreadLocal的工作原理
public class ThreadLocal<T> {
// 每个Thread对象有一个ThreadLocalMap
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null) {
Entry e = map.getEntry(this);
if (e != null)
return (T)e.value;
}
return setInitialValue();
}
public void remove() {
ThreadLocalMap map = getMap(t);
if (map != null)
map.remove(this);
}
}6.2 Thread对象的ThreadLocalMap
public class Thread {
// 每个线程有自己的ThreadLocalMap
ThreadLocal.ThreadLocalMap threadLocals = null;
}内存结构:
Thread对象
└─ threadLocals (ThreadLocalMap)
├─ Entry1: key=resources ThreadLocal, value=Map<DataSource, ConnectionHolder>
├─ Entry2: key=synchronizations ThreadLocal, value=Set<TransactionSynchronization>
├─ Entry3: key=currentTransactionName, value="UserService.createUser"
└─ Entry4: key=actualTransactionActive, value=true6.3 内存泄漏问题
问题:ThreadLocal的key是弱引用,但value是强引用
ThreadLocal实例 → 弱引用 → 可能被GC回收
但ThreadLocalMap中的value → 强引用 → 不会被回收
如果ThreadLocal被回收,但value还在,就会内存泄漏!解决方案:使用完必须调用remove()
try {
resources.set(map);
// 使用资源
} finally {
resources.remove(); // 必须清理!
}Spring的处理:
private static Object doUnbindResource(Object actualKey) {
Map<Object, Object> map = resources.get();
if (map == null) {
return null;
}
Object value = map.remove(actualKey);
// 如果Map为空,清理ThreadLocal
if (map.isEmpty()) {
resources.remove(); // ← 防止内存泄漏
}
return value;
}七、完整的事务生命周期中的ThreadLocal变化
7.1 事务开始前
ThreadLocal状态:
resources: null
synchronizations: null
currentTransactionName: null
actualTransactionActive: null7.2 事务开始(doBegin后)
// AbstractPlatformTransactionManager.startTransaction
doBegin(transaction, definition);
prepareSynchronization(status, definition) {
setActualTransactionActive(true);
setCurrentTransactionName(definition.getName());
setCurrentTransactionIsolationLevel(definition.getIsolationLevel());
setCurrentTransactionReadOnly(definition.isReadOnly());
initSynchronization();
}ThreadLocal状态:
resources: {
DataSource → ConnectionHolder
}
synchronizations: LinkedHashSet<TransactionSynchronization>
currentTransactionName: "UserService.createUser"
currentTransactionIsolationLevel: null
currentTransactionReadOnly: null
actualTransactionActive: true7.3 业务执行中
// MyBatis注册SqlSession同步
TransactionSynchronizationManager.bindResource(sqlSessionFactory, sqlSessionHolder);
TransactionSynchronizationManager.registerSynchronization(sqlSessionSynchronization);ThreadLocal状态:
resources: {
DataSource → ConnectionHolder,
SqlSessionFactory → SqlSessionHolder
}
synchronizations: {
ConnectionSynchronization,
SqlSessionSynchronization
}
currentTransactionName: "UserService.createUser"
actualTransactionActive: true7.4 事务提交后
// AbstractPlatformTransactionManager.processCommit
triggerBeforeCommit(status);
doCommit(status);
triggerAfterCommit(status);
cleanupAfterCompletion(status);ThreadLocal状态:
resources: null (已清理)
synchronizations: null (已清理)
currentTransactionName: null (已清理)
actualTransactionActive: false (已清理)7.5 事务回滚后
// AbstractPlatformTransactionManager.processRollback
triggerBeforeCompletion(status);
doRollback(status);
cleanupAfterCompletion(status);ThreadLocal状态:
resources: null (已清理)
synchronizations: null (已清理)
currentTransactionName: null (已清理)
actualTransactionActive: false (已清理)八、关键问题解答
Q1:为什么使用ThreadLocal而不是其他线程安全机制?
对比方案:
| 方案 | 优点 | 缺点 |
|---|---|---|
| synchronized | 简单 | 性能差,阻塞 |
| ConcurrentHashMap | 并发好 | 需要管理所有线程的资源 |
| ThreadLocal | 无锁,性能好 | 需要注意内存泄漏 |
ThreadLocal的优势:
- 无锁:每个线程独立,无需同步
- 高性能:没有竞争
- 天然隔离:线程之间完全隔离
Q2:线程池环境下,线程复用会导致问题吗?
不会,原因:
- 事务完成后ThreadLocal被清理:
cleanupAfterCompletion() {
clearSynchronization();
resources.remove();
actualTransactionActive.remove();
// ThreadLocal完全清理
}- 线程复用时,状态是干净的:
线程1执行事务A:
ThreadLocal设置状态
事务提交
ThreadLocal清理
线程归还到线程池
线程1被复用,执行事务B:
ThreadLocal为null (干净的)
重新设置状态Q3:父子线程如何传递事务上下文?
问题:ThreadLocal不自动传递给子线程
@Transactional
public void parentMethod() {
// 父线程有事务上下文
CompletableFuture.runAsync(() -> {
// 子线程没有事务上下文!
// ThreadLocal不会自动传递
});
}解决方案:使用InheritableThreadLocal(Spring未使用)或手动传递
// 手动传递
Map<Object, Object> context = TransactionSynchronizationManager.getResourceMap();
CompletableFuture.runAsync(() -> {
// 手动设置上下文
// 但通常不建议跨线程共享事务
});最佳实践:不要在子线程中使用父线程的事务!
Q4:多数据源事务如何协调?
@Transactional
public void multiDataSourceMethod() {
// 主数据源
jdbcTemplatePrimary.update(...);
// 副数据源
jdbcTemplateSecondary.update(...);
// 两个数据源的连接都绑定到同一个ThreadLocal
}ThreadLocal状态:
resources: {
PrimaryDataSource → ConnectionHolder1,
SecondaryDataSource → ConnectionHolder2
}问题:如果副数据源操作失败,主数据源如何回滚?
解决方案:使用JTA(分布式事务)或Seata
// JTA事务管理器
@Bean
public PlatformTransactionManager transactionManager() {
return new JtaTransactionManager();
}九、总结
通过本文的深入分析,我们完整理解了TransactionSynchronizationManager的ThreadLocal机制:
- 资源管理:
bindResource、getResource、unbindResource - 同步管理:
initSynchronization、registerSynchronization、触发回调 - 事务上下文:名称、隔离级别、只读标记、活跃状态
- ThreadLocal底层:每个线程独立的ThreadLocalMap
- 内存泄漏防护:及时清理,
remove()调用 - 线程池兼容:事务完成后清理,线程复用安全
十、系列总结
至此,我们完成了Spring事务管理的第一阶段学习:
第一篇:@Transactional注解的幕后英雄
@EnableTransactionManagement激活事务管理TransactionManagementConfigurationSelector导入配置InfrastructureAdvisorAutoProxyCreator创建代理- 三大核心组件:属性源、拦截器、通知器
第二篇:事务的起点
TransactionInterceptor.invoke方法拦截invokeWithinTransaction核心流程- 事务属性解析与缓存
createTransactionIfNecessary创建事务
第三篇:事务管理器的核心
AbstractPlatformTransactionManager模板方法模式- 七种传播行为的完整实现
- 事务挂起与恢复机制
- 事务提交、回滚、清理流程
第四篇:JDBC事务的实现
DataSourceTransactionManager的具体实现doBegin获取连接、关闭自动提交doCommit、doRollback的JDBC调用- 连接池的协作机制
第五篇:ThreadLocal的魔法
TransactionSynchronizationManager的资源管理- ThreadLocal的底层实现
- 事务同步回调机制
- 内存泄漏防护
十一、后续系列预告
系列二:数据源与连接池
- Druid连接池的原理与Spring集成
- Spring Boot自动配置数据源的机制
- HikariCP vs Druid vs Tomcat JDBC
系列三:MyBatis与事务
- MyBatis如何获取Spring管理的Connection
- SqlSession的线程安全设计
- MyBatis-Spring的集成原理
系列四:MySQL驱动与JDBC
- MySQL JDBC驱动的底层实现
- PreparedStatement的执行流程
- 结果集的处理机制
系列五:完整链路总结
- 从@Transactional到MySQL服务器的全链路
- 时序图与架构图
- 常见问题与最佳实践
参考资料
- Spring Framework 5.3.x 源码
spring-tx/src/main/java/org/springframework/transaction/support/TransactionSynchronizationManager.java- JDK源码:
java.lang.ThreadLocal - 《Spring源码深度解析》
- 《Effective Java》- Item 73: Avoid threads when possible