part5-transaction-synchronization-manager
约 4259 字大约 14 分钟
2026-05-24
系列文章:《深入Spring事务与数据源:从注解到数据库连接的全链路解析》
系列一第5篇:TransactionSynchronizationManager源码深度解析
基于版本:Spring Framework 5.3.x
前置阅读:第四篇:DataSourceTransactionManager与数据源的绑定
前言
终于到了系列一的最后一篇!
前四篇文章咱们追本溯源,从@Transactional注解一路追到了Connection.commit(),整个事务管理的流程算是搞清楚了。
但是,有个幕后英雄咱们一直没深入聊——TransactionSynchronizationManager。
你可能不知道,这个类可以说是整个Spring事务管理的"基础设施"。它干了啥呢?简单说:
- 用ThreadLocal保存当前线程的事务资源(连接、session等)
- 管理事务同步回调(事务提交/回滚前后要执行的逻辑)
- 保证同一个线程内的事务能共享同一个连接
你说重要不重要?
而且我敢说,很多开发者用了好几年Spring,都不清楚ThreadLocal在事务管理中是怎么工作的,更不知道如果不小心就会造成内存泄漏!
今天,咱们就来把这个"幕后英雄"扒个底朝天。看完这篇文章,你会对ThreadLocal、事务同步、资源管理有一个全新的认识。
一、再回顾一下:Spring Boot是怎么激活事务管理的?
在深入源码之前,咱们还是快速回顾一下自动装配的入口。毕竟这是咱们系列的传统了,对吧?
核心入口:TransactionAutoConfiguration
文件位置:spring-boot-autoconfigure/TransactionAutoConfiguration.java
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(PlatformTransactionManager.class)
@AutoConfigureAfter({ JtaAutoConfiguration.class, HibernateJpaAutoConfiguration.class,
DataSourceTransactionManagerAutoConfiguration.class, Neo4jDataAutoConfiguration.class })
@EnableConfigurationProperties(TransactionProperties.class)
public class TransactionAutoConfiguration {
@Configuration(proxyBeanMethods = false)
@ConditionalOnMissingBean(PlatformTransactionManager.class)
static class EnableTransactionManagementConfiguration {
@Configuration(proxyBeanMethods = false)
@EnableTransactionManagement(proxyTargetClass = true) // 默认使用CGLIB代理
@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class",
havingValue = "true", matchIfMissing = true)
static class CglibAutoProxyConfiguration {
}
}
}这个配置类激活了@EnableTransactionManagement,然后导入了TransactionManagementConfigurationSelector,最终注册了TransactionInterceptor、TransactionAttributeSource等组件。
而TransactionSynchronizationManager虽然没有显式注册,但它是被DataSourceTransactionManager等方法隐式使用的。
好了,回顾完毕,正式进入咱们的主题!
二、TransactionSynchronizationManager:事务资源的大管家
先来看看这个类的整体结构:
核心类:TransactionSynchronizationManager
文件位置:spring-tx/TransactionSynchronizationManager.java
public abstract class TransactionSynchronizationManager {
// ========== 六大ThreadLocal变量 ==========
// 1. 当前线程的事务资源映射
// key是资源(比如DataSource),value是资源持有者(比如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
public static void bindResource(Object key, Object value) { }
// 从ThreadLocal获取资源
public static Object getResource(Object key) { }
// 从ThreadLocal解绑资源
public static Object unbindResource(Object key) { }
// 注册事务同步回调
public static void registerSynchronization(TransactionSynchronization synchronization) { }
// 初始化事务同步
public static void initSynchronization() { }
// 清除事务同步
public static void clearSynchronization() { }
// ... 其他方法
}看到没?这个类的核心就是六个ThreadLocal变量!
这六个ThreadLocal保存了当前线程的所有事务信息,构成了事务管理的"基础设施"。
扩展场景1:为什么用ThreadLocal?
因为事务是跟线程绑定的!同一个线程内的所有操作,都应该使用同一个事务、同一个连接。
// 线程A
@Transactional
public void methodA() {
// 获取连接1
Connection con = dataSource.getConnection();
methodB(); // methodB也要用连接1
}
// 线程B
@Transactional
public void methodC() {
// 获取连接2(和线程A的连接不同)
Connection con = dataSource.getConnection();
}用ThreadLocal可以保证:
- 线程A和线程B的资源互不干扰
- 线程A内的methodA和methodB共享同一个连接
扩展场景2:NamedThreadLocal是啥?
就是一个普通的ThreadLocal,只是多了个名字,方便调试:
public class NamedThreadLocal<T> extends ThreadLocal<T> {
private final String name;
public NamedThreadLocal(String name) {
this.name = name;
}
@Override
public String toString() {
return this.name;
}
}三、bindResource:绑定资源到ThreadLocal
好,现在来看第一个核心方法——bindResource():
核心方法1:bindResource
文件位置:spring-tx/TransactionSynchronizationManager.java
public static void bindResource(Object key, Object value) throws IllegalStateException {
// 获取实际的key(如果需要解包装)
Object actualKey = TransactionSynchronizationUtils.unwrapResourceIfNecessary(key);
Assert.notNull(value, "Value must not be null");
// ========== 第一步:获取ThreadLocal中的Map ==========
// resources是一个ThreadLocal<Map<Object, Object>>
// 每个线程都有自己的Map
Map<Object, Object> map = resources.get();
// ========== 第二步:如果Map为空,创建新Map并设置到ThreadLocal ==========
if (map == null) {
map = new HashMap<>();
resources.set(map); // ★★★★★ 核心:设置到ThreadLocal ★★★★★
}
// ========== 第三步:将资源放入Map ==========
// key是DataSource,value是ConnectionHolder
Object oldValue = map.put(actualKey, value);
// ========== 第四步:检查是否重复绑定 ==========
// 如果已经绑定了,抛异常
// 这通常意味着代码有bug
if (oldValue instanceof ResourceHolder &&
!((ResourceHolder) oldValue).isVoid()) {
throw new IllegalStateException(
"Already value [" + oldValue + "] for key [" + actualKey +
"] bound to thread [" + Thread.currentThread().getName() + "]");
}
if (logger.isTraceEnabled()) {
logger.trace("Bound value [" + value + "] for key [" + actualKey +
"] to thread [" + Thread.currentThread().getName() + "]");
}
}这个方法干了三件事:
- 获取ThreadLocal中的Map(如果为空,创建新Map)
- 把资源放入Map(key是DataSource,value是ConnectionHolder)
- 检查是否重复绑定(防止bug)
关键点:resources的结构是这样的:
ThreadLocal {
Thread A: Map {
DataSource1 -> ConnectionHolder1
DataSource2 -> ConnectionHolder2
}
Thread B: Map {
DataSource1 -> ConnectionHolder3
DataSource2 -> ConnectionHolder4
}
}每个线程都有自己的Map,每个Map可以存多个DataSource对应的ConnectionHolder。
扩展场景3:什么时候会调用bindResource?
在DataSourceTransactionManager.doBegin()中:
@Override
protected void doBegin(Object transaction, TransactionDefinition definition) {
// ... 获取连接,关闭autocommit
// ★★★★★ 绑定连接到ThreadLocal ★★★★★
TransactionSynchronizationManager.bindResource(
obtainDataSource(), txObject.getConnectionHolder());
}四、getResource:从ThreadLocal获取资源
绑定完了,怎么获取呢?
核心方法2:getResource
文件位置:spring-tx/TransactionSynchronizationManager.java
public static Object getResource(Object key) {
// 获取实际的key
Object actualKey = TransactionSynchronizationUtils.unwrapResourceIfNecessary(key);
// ★★★★★ 核心:调用doResource获取资源 ★★★★★
Object value = doGetResource(actualKey);
if (value != null && logger.isTraceEnabled()) {
logger.trace("Retrieved value [" + value + "] for key [" + actualKey +
"] bound to thread [" + Thread.currentThread().getName() + "]");
}
return value;
}
private static Object doGetResource(Object actualKey) {
// ========== 第一步:获取ThreadLocal中的Map ==========
Map<Object, Object> map = resources.get();
// ========== 第二步:如果Map为空,返回null ==========
if (map == null) {
return null;
}
// ========== 第三步:从Map中获取资源 ==========
Object value = map.get(actualKey);
// ========== 第四步:如果资源已销毁,移除并返回null ==========
// 这是为了防止使用已失效的资源
if (value instanceof ResourceHolder &&
((ResourceHolder) value).isVoid()) {
map.remove(actualKey);
if (map.isEmpty()) {
// 如果Map空了,清理ThreadLocal
resources.remove();
}
value = null;
}
return value;
}这个方法很简单:
- 获取ThreadLocal中的Map
- 从Map中获取资源
- 如果资源已失效,移除并返回null
扩展场景4:什么时候会调用getResource?
在DataSourceTransactionManager.doGetTransaction()中:
@Override
protected Object doGetTransaction() {
DataSourceTransactionObject txObject = new DataSourceTransactionObject();
// ★★★★★ 从ThreadLocal获取连接 ★★★★★
ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager
.getResource(this.dataSource);
txObject.setConnectionHolder(conHolder, false);
return txObject;
}五、unbindResource:从ThreadLocal解绑资源
事务完成后,必须解绑资源,否则会导致内存泄漏!
核心方法3:unbindResource
文件位置:spring-tx/TransactionSynchronizationManager.java
public static Object unbindResource(Object key) throws IllegalStateException {
// 获取实际的key
Object actualKey = TransactionSynchronizationUtils.unwrapResourceIfNecessary(key);
// ★★★★★ 核心:调用doUnbindResource解绑 ★★★★★
Object value = doUnbindResource(actualKey);
if (value == null) {
throw new IllegalStateException(
"No value for key [" + actualKey +
"] bound to thread [" + Thread.currentThread().getName() + "]");
}
return value;
}
private static Object doUnbindResource(Object actualKey) {
// ========== 第一步:获取ThreadLocal中的Map ==========
Map<Object, Object> map = resources.get();
// ========== 第二步:如果Map为空,返回null ==========
if (map == null) {
return null;
}
// ========== 第三步:从Map中移除资源 ==========
Object value = map.remove(actualKey);
// ========== 第四步:如果Map空了,清理ThreadLocal ==========
// ★★★★★ 重要:防止内存泄漏 ★★★★★
if (map.isEmpty()) {
resources.remove(); // ★★★★★ 核心:清理ThreadLocal ★★★★★
}
if (value != null && logger.isTraceEnabled()) {
logger.trace("Removed value [" + value + "] for key [" + actualKey +
"] from thread [" + Thread.currentThread().getName() + "]");
}
return value;
}这个方法的关键是:
- 从Map中移除资源
- 如果Map空了,调用
resources.remove()清理ThreadLocal
关键点:为什么要清理ThreadLocal?
因为ThreadLocal的生命周期和线程一样长。如果不清理,线程池中的线程复用后,还会持有旧的引用,导致内存泄漏!
扩展场景5:ThreadLocal内存泄漏的场景
// 错误示例:没有清理ThreadLocal
public void method() {
TransactionSynchronizationManager.bindResource(dataSource, connectionHolder);
// ... 使用资源
// 方法结束,但没有调用unbindResource
}
// 在线程池中:
// 线程1执行method(),绑定了资源
// 线程1归还到线程池
// 线程1再次被使用,但ThreadLocal中还有旧的引用
// 内存泄漏!正确做法:
public void method() {
try {
TransactionSynchronizationManager.bindResource(dataSource, connectionHolder);
// ... 使用资源
} finally {
// ★★★★★ 必须在finally中清理 ★★★★★
TransactionSynchronizationManager.unbindResource(dataSource);
}
}六、unbindResourceIfPossible:安全解绑
有时候,资源可能不存在,直接调用unbindResource会抛异常。这时候可以用unbindResourceIfPossible:
核心方法4:unbindResourceIfPossible
文件位置:spring-tx/TransactionSynchronizationManager.java
@Nullable
public static Object unbindResourceIfPossible(Object key) {
try {
return unbindResource(key);
}
catch (IllegalStateException ex) {
return null;
}
}就一个try-catch,如果资源不存在,返回null而不是抛异常。
这个方法在DataSourceTransactionManager.doCleanupAfterCompletion()中被调用:
@Override
protected void doCleanupAfterCompletion(Object transaction) {
// ★★★★★ 安全解绑,即使资源不存在也不抛异常 ★★★★★
TransactionSynchronizationManager.unbindResourceIfPossible(obtainDataSource());
}七、initSynchronization:初始化事务同步
除了管理资源,TransactionSynchronizationManager还管理事务同步回调。
什么是事务同步回调?简单说,就是事务提交/回滚前后要执行的逻辑。
核心方法5:initSynchronization
文件位置:spring-tx/TransactionSynchronizationManager.java
public static void initSynchronization() throws IllegalStateException {
// 检查是否已经初始化
if (isSynchronizationActive()) {
throw new IllegalStateException(
"Transaction synchronization is already active");
}
// ★★★★★ 核心:创建一个新的HashSet,保存到ThreadLocal ★★★★★
synchronizations.set(new LinkedHashSet<>());
if (logger.isDebugEnabled()) {
logger.debug("Initializing transaction synchronization");
}
}这个方法就是创建了一个LinkedHashSet,保存到ThreadLocal中,用来存放事务同步回调。
关键点:TransactionSynchronization是啥?
核心接口:TransactionSynchronization
文件位置:spring-tx/TransactionSynchronization.java
public interface TransactionSynchronization extends Flushable {
// 事务完成后的状态常量
int STATUS_COMMITTED = 0; // 已提交
int STATUS_ROLLED_BACK = 1; // 已回滚
int STATUS_UNKNOWN = 2; // 未知
// 挂起事务时调用
default void suspend() { }
// 恢复事务时调用
default void resume() { }
// 刷新(Flushable接口的方法)
@Override
default void flush() { }
// 事务提交前调用
default void beforeCommit(boolean readOnly) { }
// 事务完成前调用(提交或回滚前)
default void beforeCompletion() { }
// 事务提交后调用
default void afterCommit() { }
// 事务完成后调用(提交或回滚后)
default void afterCompletion(int status) { }
}这个接口定义了一系列回调方法,可以在事务的不同阶段执行自定义逻辑。
扩展场景6:如何注册事务同步回调?
@Service
public class OrderService {
@Transactional
public void createOrder(Order order) {
// 创建订单
orderMapper.insert(order);
// ★★★★★ 注册事务同步回调 ★★★★★
TransactionSynchronizationManager.registerSynchronization(
new TransactionSynchronization() {
@Override
public void afterCommit() {
// 事务提交后发送MQ消息
mqSender.send("order.created", order.getId());
}
@Override
public void afterCompletion(int status) {
if (status == STATUS_COMMITTED) {
System.out.println("订单创建成功");
} else if (status == STATUS_ROLLED_BACK) {
System.out.println("订单创建失败");
}
}
}
);
}
}这样,事务提交后会自动发送MQ消息,不用手动处理。
八、registerSynchronization:注册事务同步回调
核心方法6:registerSynchronization
文件位置:spring-tx/TransactionSynchronizationManager.java
public static void registerSynchronization(TransactionSynchronization synchronization)
throws IllegalStateException {
Assert.notNull(synchronization, "TransactionSynchronization must not be null");
// 检查事务同步是否激活
if (!isSynchronizationActive()) {
throw new IllegalStateException(
"Transaction synchronization is not active");
}
// ★★★★★ 核心:将回调添加到ThreadLocal的Set中 ★★★★★
synchronizations.get().add(synchronization);
}很简单,就是把回调添加到ThreadLocal的Set中。
九、事务同步回调的触发
注册了回调,什么时候触发呢?
核心方法7:triggerBeforeCommit
文件位置:spring-tx/TransactionSynchronizationManager.java
public static void triggerBeforeCommit(boolean readOnly) {
// 获取所有回调
for (TransactionSynchronization synchronization : getSynchronizations()) {
try {
// ★★★★★ 调用beforeCommit方法 ★★★★★
synchronization.beforeCommit(readOnly);
}
catch (RuntimeException | Error ex) {
printStackTraceIfNecessary(ex);
throw ex;
}
}
}核心方法8:triggerAfterCommit
文件位置:spring-tx/TransactionSynchronizationManager.java
public static void triggerAfterCommit() {
invokeAfterCommit(getSynchronizations());
}
private static void invokeAfterCommit(List<TransactionSynchronization> synchronizations) {
if (synchronizations != null) {
for (TransactionSynchronization synchronization : synchronizations) {
try {
// ★★★★★ 调用afterCommit方法 ★★★★★
synchronization.afterCommit();
}
catch (RuntimeException | Error ex) {
printStackTraceIfNecessary(ex);
throw ex;
}
}
}
}核心方法9:triggerAfterCompletion
文件位置:spring-tx/TransactionSynchronizationManager.java
public static void triggerAfterCompletion(int status) {
invokeAfterCompletion(getSynchronizations(), status);
}
private static void invokeAfterCompletion(
@Nullable List<TransactionSynchronization> synchronizations, int status) {
if (synchronizations != null) {
for (TransactionSynchronization synchronization : synchronizations) {
try {
// ★★★★★ 调用afterCompletion方法,传入状态 ★★★★★
synchronization.afterCompletion(status);
}
catch (RuntimeException | Error ex) {
printStackTraceIfNecessary(ex);
throw ex;
}
}
}
}这些方法在AbstractPlatformTransactionManager.processCommit()和processRollback()中被调用:
private void processCommit(DefaultTransactionStatus status) {
try {
// ...
// 触发beforeCommit回调
triggerBeforeCommit(status);
// 执行提交
doCommit(status);
// 触发afterCommit回调
triggerAfterCommit(status);
// 触发afterCompletion回调
triggerAfterCompletion(status, TransactionSynchronization.STATUS_COMMITTED);
}
finally {
cleanupAfterCompletion(status);
}
}十、clearSynchronization:清理事务同步
事务完成后,要清理同步回调:
核心方法10:clearSynchronization
文件位置:spring-tx/TransactionSynchronizationManager.java
public static void clearSynchronization() throws IllegalStateException {
if (!isSynchronizationActive()) {
throw new IllegalStateException(
"Transaction synchronization is not active");
}
// ★★★★★ 核心:清理ThreadLocal ★★★★★
synchronizations.remove();
if (logger.isDebugEnabled()) {
logger.debug("Cleared transaction synchronization");
}
}同样是清理ThreadLocal,防止内存泄漏。
十一、完整的事务资源管理流程图
说了这么多,咱们画个图把整个流程串起来:
事务开始
↓
┌────────────────────────────────────────────┐
│ TransactionSynchronizationManager │
│ │
│ 1. initSynchronization() │
│ → 创建LinkedHashSet │
│ → 保存到ThreadLocal │
│ │
│ 2. bindResource(dataSource, connHolder) │
│ → 获取ThreadLocal中的Map │
│ → 如果为空,创建新Map │
│ → 将资源放入Map │
│ → key: DataSource │
│ → value: ConnectionHolder │
└─────────────┬───────────────────────────────┘
↓
┌────────────────────────────────────────────┐
│ 执行业务方法 │
│ │
│ → getResource(dataSource) │
│ → 从ThreadLocal的Map中获取 │
│ → 返回ConnectionHolder │
│ │
│ → registerSynchronization(callback) │
│ → 添加回调到ThreadLocal的Set │
└─────────────┬───────────────────────────────┘
↓
┌────────────────────────────────────────────┐
│ 事务提交 │
│ │
│ → triggerBeforeCommit() │
│ → 调用所有回调的beforeCommit() │
│ │
│ → doCommit() │
│ → connection.commit() │
│ │
│ → triggerAfterCommit() │
│ → 调用所有回调的afterCommit() │
│ │
│ → triggerAfterCompletion(STATUS_COMMITTED) │
│ → 调用所有回调的afterCompletion() │
└─────────────┬───────────────────────────────┘
↓
┌────────────────────────────────────────────┐
│ 清理资源 │
│ │
│ → unbindResourceIfPossible(dataSource) │
│ → 从Map中移除资源 │
│ → 如果Map为空,清理ThreadLocal │
│ │
│ → clearSynchronization() │
│ → 清理ThreadLocal的Set │
│ │
│ → 清理其他ThreadLocal变量 │
│ → currentTransactionName │
│ → currentTransactionReadOnly │
│ → currentTransactionIsolationLevel │
│ → actualTransactionActive │
└────────────────────────────────────────────┘十二、关键问题解答
Q1:ThreadLocal的内存模型是怎样的?
Thread {
ThreadLocalMap {
ThreadLocal -> Value
ThreadLocal -> Value
}
}
// 实际结构:
Thread A {
ThreadLocalMap {
resources (ThreadLocal) -> Map {
DataSource1 -> ConnectionHolder1
}
synchronizations (ThreadLocal) -> Set {
callback1, callback2
}
}
}每个Thread有自己的ThreadLocalMap,每个ThreadLocal是Map的一个key。
Q2:为什么用Map而不是直接存ConnectionHolder?
因为一个线程可能访问多个数据源,每个数据源对应一个连接。用Map可以存多个:
Map {
DataSource1 -> ConnectionHolder1
DataSource2 -> ConnectionHolder2
DataSource3 -> ConnectionHolder3
}Q3:线程池场景下,ThreadLocal怎么保证安全?
关键是用完就清理!
try {
bindResource(key, value);
// 使用资源
} finally {
unbindResource(key); // 必须清理
clearSynchronization(); // 必须清理
}只要保证每次用完都清理,线程复用就不会有问题。
Q4:如果忘记清理ThreadLocal会怎样?
内存泄漏!
线程池中的线程:
1. 执行任务A,绑定了资源
2. 任务A结束,但没有清理
3. 线程归还到线程池
4. 执行任务B,但ThreadLocal中还有任务A的资源
5. 内存泄漏!
严重情况下,会导致:
- OutOfMemoryError
- 连接无法释放
- 事务混乱十三、扩展:TransactionSynchronization的实际应用
扩展场景7:使用TransactionSynchronizationAdapter简化回调
@Service
public class UserService {
@Transactional
public void createUser(User user) {
userMapper.insert(user);
// 使用适配器,不用实现所有方法
TransactionSynchronizationManager.registerSynchronization(
new TransactionSynchronizationAdapter() {
@Override
public void afterCommit() {
// 事务提交后发送邮件
emailService.sendWelcomeEmail(user.getEmail());
}
}
);
}
}扩展场景8:使用@TransactionalEventListener替代手动注册
Spring 4.2之后,可以用@TransactionalEventListener更优雅地处理事务事件:
@Component
public class OrderEventListener {
// 事务提交后触发
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
public void handleOrderCreated(OrderCreatedEvent event) {
// 发送MQ消息
mqSender.send("order.created", event.getOrderId());
}
// 事务回滚后触发
@TransactionalEventListener(phase = TransactionPhase.AFTER_ROLLBACK)
public void handleOrderFailed(OrderCreatedEvent event) {
// 记录失败日志
log.error("订单创建失败:" + event.getOrderId());
}
}
@Service
public class OrderService {
@Autowired
private ApplicationEventPublisher eventPublisher;
@Transactional
public void createOrder(Order order) {
orderMapper.insert(order);
// 发布事件(不会立即触发回调)
eventPublisher.publishEvent(new OrderCreatedEvent(order.getId()));
}
}这种方式更解耦,推荐使用!
十四、系列一总结
通过这五篇文章,咱们完整追踪了Spring事务管理的全链路:
第一篇:@Transactional注解的幕后英雄
@EnableTransactionManagement的激活机制ProxyTransactionManagementConfiguration的三大组件InfrastructureAdvisorAutoProxyCreator创建代理
第二篇:TransactionInterceptor如何开启一个事务
invokeWithinTransaction()的完整流程- 事务属性解析与缓存
- 事务管理器查找策略
- 异常处理和回滚规则
第三篇:AbstractPlatformTransactionManager的事务生命周期
- 七种传播行为的完整实现
- 事务挂起与恢复机制
- 事务提交、回滚、清理流程
第四篇:DataSourceTransactionManager与数据源的绑定
doBegin()的8个步骤con.setAutoCommit(false)的底层实现- 连接池协作机制
第五篇:TransactionSynchronizationManager资源管理揭秘
- 六大ThreadLocal变量详解
bindResource/getResource/unbindResource完整实现- 事务同步回调机制
- 内存泄漏防护
整个流程串起来就是:
1. @EnableTransactionManagement激活事务管理
2. 为Bean创建代理对象
3. 调用代理方法,进入TransactionInterceptor
4. 解析@Transactional注解,获取事务属性
5. 查找事务管理器
6. 调用tm.getTransaction()创建事务
→ doGetTransaction()检查ThreadLocal
→ doBegin()获取连接,关闭autocommit,绑定ThreadLocal
7. 执行业务方法
8. 成功则commit,失败则rollback
→ doCommit()或doRollback()
9. 清理资源
→ 解绑ThreadLocal,释放连接十五、系列二预告:数据源与连接池
系列一到这里就圆满结束了!但是,咱们还有一个关键问题没深入:
连接是怎么获取的?
dataSource.getConnection()的底层实现是啥?- Druid、HikariCP这些连接池是怎么工作的?
- 连接池怎么保证线程安全?
- 连接池怎么做连接有效性检测?
- 连接池的监控是怎么实现的?
这些问题,将在下一个系列《数据源与连接池全链路源码解析》中为你揭晓。到时候咱们会深入到Druid的源码,看看它是怎么管理连接的,Filter链是怎么工作的,监控数据是怎么收集的。
敬请期待系列二!
参考资料
- Spring Framework 5.3.x 源码
spring-tx/src/main/java/org/springframework/transaction/support/TransactionSynchronizationManager.javaspring-tx/src/main/java/org/springframework/transaction/support/TransactionSynchronization.java
- 《Spring源码深度解析》
- 《Java并发编程实战》- ThreadLocal章节