SpringBoot事务源码深度游:从注解到数据库的"奇幻漂流" 🧙♂️🔍
各位Java大侠,上回我们聊了SpringBoot事务的"表面功夫",今天咱们来个深度解剖 ,看看当你潇洒地写下@Transactional时,SpringBoot在背后到底干了多少"脏活累活"。准备好你的IDE,咱们一起开启源码之旅!🚀
第一章:@Transactional的"前世今生"------注解解析全流程 📖
1.1 注解的"出生证明"
当你写@Transactional时,Spring是怎么知道要处理它的?
关键类 :TransactionInterceptor、AnnotationTransactionAttributeSource、BeanFactoryTransactionAttributeSourceAdvisor
less
// 1. 首先,Spring启动时,@EnableTransactionManagement注解开启事务支持
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Import(TransactionManagementConfigurationSelector.class)
public @interface EnableTransactionManagement {
// 代理模式:CGLIB 还是 JDK动态代理?
AdviceMode mode() default AdviceMode.PROXY;
// 代理顺序
int order() default Ordered.LOWEST_PRECEDENCE;
}
执行流程:
markdown
// 简化版调用链
1. 容器启动 → @EnableTransactionManagement生效
2. → 注册 InfrastructureAdvisorAutoProxyCreator(AOP代理创建器)
3. → 扫描所有Bean,找@Transactional注解的方法
4. → 创建代理对象,将TransactionInterceptor作为增强
5. → 调用代理方法时,进入TransactionInterceptor.invoke()
1.2 TransactionInterceptor的核心invoke()方法
这是事务的总入口,让我们看看它的真面目:
scala
// org.springframework.transaction.interceptor.TransactionInterceptor
public class TransactionInterceptor extends TransactionAspectSupport
implements MethodInterceptor, Serializable {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
// 获取目标类
Class<?> targetClass = (invocation.getThis() != null ?
AopUtils.getTargetClass(invocation.getThis()) : null);
// 关键!调用父类的invokeWithinTransaction方法
return invokeWithinTransaction(
invocation.getMethod(), // 被调用的方法
targetClass, // 目标类
invocation::proceed // 实际要执行的业务方法
);
}
}
第二章:invokeWithinTransaction------事务的"心脏" ❤️
这才是真正的事务处理核心 ,代码在父类TransactionAspectSupport中:
java
// org.springframework.transaction.interceptor.TransactionAspectSupport
protected Object invokeWithinTransaction(Method method,
@Nullable Class<?> targetClass,
final InvocationCallback invocation) throws Throwable {
// 1️⃣ 获取事务属性(@Transactional注解的配置)
TransactionAttributeSource tas = getTransactionAttributeSource();
final TransactionAttribute txAttr = (tas != null ?
tas.getTransactionAttribute(method, targetClass) : null);
// 2️⃣ 确定事务管理器
final PlatformTransactionManager tm = determineTransactionManager(txAttr);
// 3️⃣ 构造方法标识(用于日志和监控)
final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);
// 4️⃣ 声明式事务处理
if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {
// 🔥 关键!获取事务状态
TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
Object retVal = null;
try {
// 5️⃣ 执行真正的业务逻辑
retVal = invocation.proceedWithInvocation();
}
catch (Throwable ex) {
// 6️⃣ 异常处理:回滚或提交
completeTransactionAfterThrowing(txInfo, ex);
throw ex;
}
finally {
// 7️⃣ 清理线程绑定的资源
cleanupTransactionInfo(txInfo);
}
// 8️⃣ 提交事务
commitTransactionAfterReturning(txInfo);
return retVal;
}
else {
// 编程式事务处理(略)
}
}
第三章:createTransactionIfNecessary------事务的"诞生" 👶
这个方法决定了是否创建新事务、如何传播事务:
less
// TransactionAspectSupport.createTransactionIfNecessary
protected TransactionInfo createTransactionIfNecessary(
@Nullable PlatformTransactionManager tm,
@Nullable TransactionAttribute txAttr,
final String joinpointIdentification) {
// 如果transaction属性为空,则创建一个空事务
if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {
// 1. 获取现有事务(可能为null)
TransactionStatus status = null;
if (txAttr != null) {
if (tm != null) {
// 🔥 关键!调用事务管理器的getTransaction方法
status = tm.getTransaction(txAttr);
}
}
// 2. 准备事务信息
return prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
}
// ...
}
3.1 tm.getTransaction()------传播行为的实现
这是各种传播行为的实现核心 ,在AbstractPlatformTransactionManager中:
java
// AbstractPlatformTransactionManager.getTransaction
public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition)
throws TransactionException {
// 1. 获取事务定义(没有则用默认值)
TransactionDefinition def = (definition != null ? definition :
TransactionDefinition.withDefaults());
// 2. 🔥 获取现有事务(检查当前线程是否已有事务)
Object transaction = doGetTransaction();
// 3. 如果当前已存在事务
if (isExistingTransaction(transaction)) {
// 🔥 处理嵌套事务的情况
return handleExistingTransaction(def, transaction, debugEnabled);
}
// 4. 检查超时设置
if (def.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {
throw new InvalidTimeoutException(...);
}
// 5. 当前没有事务,但需要事务(REQUIRED, REQUIRES_NEW等)
if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {
throw new IllegalTransactionStateException(...);
}
else if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||
def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||
def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
// 🔥 关键!挂起null事务(因为当前没有事务)
SuspendedResourcesHolder suspendedResources = suspend(null);
try {
// 6. 开始新事务
return startTransaction(def, transaction, debugEnabled, suspendedResources);
}
catch (RuntimeException | Error ex) {
resume(null, suspendedResources);
throw ex;
}
}
else {
// 7. 当前不需要事务(PROPAGATION_SUPPORTS等)
boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
return prepareTransactionStatus(def, null, true, newSynchronization, debugEnabled, null);
}
}
3.2 传播行为的核心:handleExistingTransaction()
让我们看看不同传播行为在已有事务时的处理:
scss
// AbstractPlatformTransactionManager.handleExistingTransaction
private TransactionStatus handleExistingTransaction(
TransactionDefinition definition, Object transaction, boolean debugEnabled)
throws TransactionException {
// 1. NEVER:不能有事务,有就抛异常
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NEVER) {
throw new IllegalTransactionStateException(...);
}
// 2. NOT_SUPPORTED:不支持事务,挂起当前事务
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NOT_SUPPORTED) {
Object suspendedResources = suspend(transaction);
boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
return prepareTransactionStatus(
definition, null, false, newSynchronization, debugEnabled, suspendedResources);
}
// 3. REQUIRES_NEW:挂起当前事务,创建新事务
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW) {
// 挂起当前事务
SuspendedResourcesHolder suspendedResources = suspend(transaction);
try {
// 开始新事务
return startTransaction(definition, transaction, debugEnabled, suspendedResources);
}
catch (RuntimeException | Error beginEx) {
resumeAfterBeginException(transaction, suspendedResources, beginEx);
throw beginEx;
}
}
// 4. NESTED:嵌套事务
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
if (!isNestedTransactionAllowed()) {
throw new NestedTransactionNotSupportedException(...);
}
// 使用保存点(Savepoint)实现
if (useSavepointForNestedTransaction()) {
// 创建保存点
DefaultTransactionStatus status = prepareTransactionStatus(
definition, transaction, false, false, debugEnabled, null);
status.createAndHoldSavepoint();
return status;
}
else {
// 有些数据库不支持保存点,只能开启新事务
return startTransaction(definition, transaction, debugEnabled, null);
}
}
// 5. 其他(REQUIRED, SUPPORTS, MANDATORY):加入当前事务
if (isValidateExistingTransaction()) {
// 验证隔离级别、只读等设置是否匹配
}
boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
return prepareTransactionStatus(
definition, transaction, false, newSynchronization, debugEnabled, null);
}
第四章:startTransaction------开启事务的"魔法" 🪄
真正的事务开启在这里:
scss
// DataSourceTransactionManager(具体实现)
@Override
protected void doBegin(Object transaction, TransactionDefinition definition) {
DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
Connection con = null;
try {
// 1. 如果还没有连接,从数据源获取
if (!txObject.hasConnectionHolder() ||
txObject.getConnectionHolder().isSynchronizedWithTransaction()) {
Connection newCon = obtainDataSource().getConnection();
txObject.setConnectionHolder(new ConnectionHolder(newCon), true);
}
// 2. 设置连接属性
txObject.getConnectionHolder().setSynchronizedWithTransaction(true);
con = txObject.getConnectionHolder().getConnection();
// 3. 🔥 关键!设置隔离级别
Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(
con, definition);
txObject.setPreviousIsolationLevel(previousIsolationLevel);
// 4. 🔥 关键!关闭自动提交
if (con.getAutoCommit()) {
txObject.setMustRestoreAutoCommit(true);
con.setAutoCommit(false); // 就是这一行!
}
// 5. 准备事务连接
prepareTransactionalConnection(con, definition);
// 6. 设置事务状态
txObject.getConnectionHolder().setTransactionActive(true);
// 7. 设置超时
int timeout = determineTimeout(definition);
if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {
txObject.getConnectionHolder().setTimeoutInSeconds(timeout);
}
// 8. 绑定到当前线程
if (txObject.isNewConnectionHolder()) {
TransactionSynchronizationManager.bindResource(
obtainDataSource(), txObject.getConnectionHolder());
}
} catch (Throwable ex) {
// 异常处理
DataSourceUtils.releaseConnection(con, obtainDataSource());
throw new CannotCreateTransactionException(...);
}
}
看到第4步的con.setAutoCommit(false)了吗?这就是Spring事务的基石!没有它,每个SQL都会自动提交,就无法回滚了。
第五章:commitTransactionAfterReturning------提交的"艺术" 🎨
业务方法执行成功后,提交事务:
scss
// TransactionAspectSupport.commitTransactionAfterReturning
protected void commitTransactionAfterReturning(@Nullable TransactionInfo txInfo) {
if (txInfo != null && txInfo.getTransactionStatus() != null) {
txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
}
}
// AbstractPlatformTransactionManager.commit
public final void commit(TransactionStatus status) throws TransactionException {
// 1. 检查事务是否已完成
if (status.isCompleted()) {
throw new IllegalTransactionStateException(...);
}
DefaultTransactionStatus defStatus = (DefaultTransactionStatus) status;
// 2. 如果标记了回滚,则回滚
if (defStatus.isLocalRollbackOnly()) {
processRollback(defStatus, false);
return;
}
// 3. 检查是否需要全局回滚
if (!shouldCommitOnGlobalRollbackOnly() &&
defStatus.isGlobalRollbackOnly()) {
processRollback(defStatus, true);
return;
}
// 4. 🔥 真正的提交
processCommit(defStatus);
}
5.1 processCommit------真正的提交
scss
// AbstractPlatformTransactionManager.processCommit
private void processCommit(DefaultTransactionStatus status) throws TransactionException {
try {
boolean beforeCompletionInvoked = false;
try {
// 1. 触发提交前回调
prepareForCommit(status);
triggerBeforeCommit(status);
triggerBeforeCompletion(status);
beforeCompletionInvoked = true;
// 2. 如果有保存点(嵌套事务)
if (status.hasSavepoint()) {
status.releaseHeldSavepoint(); // 释放保存点,但不提交
return;
}
// 3. 如果是新事务,才真正提交
if (status.isNewTransaction()) {
doCommit(status); // 🔥 调用数据源提交
}
// 4. 如果是全局回滚
else if (status.isGlobalRollbackOnly()) {
unexpectedRollback = true;
}
}
catch (UnexpectedRollbackException ex) {
// 异常处理
}
finally {
// 5. 清理资源
cleanupAfterCompletion(status);
}
}
finally {
// ...
}
}
5.2 DataSourceTransactionManager.doCommit()
java
// DataSourceTransactionManager.doCommit
@Override
protected void doCommit(DefaultTransactionStatus status) {
DataSourceTransactionObject txObject = (DataSourceTransactionObject) status.getTransaction();
Connection con = txObject.getConnectionHolder().getConnection();
try {
con.commit(); // 🔥 JDBC提交!
} catch (SQLException ex) {
throw new TransactionSystemException("Could not commit JDBC transaction", ex);
}
}
第六章:completeTransactionAfterThrowing------回滚的"学问" 🔄
业务方法抛出异常时,决定是否回滚:
typescript
// TransactionAspectSupport.completeTransactionAfterThrowing
protected void completeTransactionAfterThrowing(@Nullable TransactionInfo txInfo, Throwable ex) {
// 1. 必须要有事务才需要回滚
if (txInfo != null && txInfo.getTransactionStatus() != null) {
// 2. 🔥 关键!判断是否应该回滚
if (txInfo.transactionAttribute != null &&
txInfo.transactionAttribute.rollbackOn(ex)) {
try {
// 3. 执行回滚
txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus());
}
catch (TransactionSystemException ex2) {
ex2.initApplicationException(ex);
throw ex2;
}
}
else {
// 4. 不应该回滚,则提交
try {
txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
}
catch (TransactionSystemException ex2) {
ex2.initApplicationException(ex);
throw ex2;
}
}
}
}
6.1 rollbackOn()------回滚判断逻辑
typescript
// RuleBasedTransactionAttribute.rollbackOn
@Override
public boolean rollbackOn(Throwable ex) {
// 1. 遍历所有回滚规则
for (RollbackRuleAttribute rule : this.rollbackRules) {
// 2. 检查异常是否匹配
if (rule.getDepth(ex) >= 0) {
return true; // 匹配,需要回滚
}
}
// 3. 默认:RuntimeException和Error回滚,CheckedException不❌
return (ex instanceof RuntimeException || ex instanceof Error);
}
这就是为什么默认情况下,IOException等Checked Exception不回滚的原因!
第七章:ThreadLocal的妙用------事务资源绑定 🧵
Spring如何保证同一个线程内,多个DAO操作用同一个连接?
核心类 :TransactionSynchronizationManager
typescript
// 内部使用ThreadLocal存储资源
public abstract class TransactionSynchronizationManager {
private static final ThreadLocal<Map<Object, Object>> resources =
new NamedThreadLocal<>("Transactional resources");
private static final ThreadLocal<Set<TransactionSynchronization>> synchronizations =
new NamedThreadLocal<>("Transaction synchronizations");
private static final ThreadLocal<String> currentTransactionName =
new NamedThreadLocal<>("Current transaction name");
private static final ThreadLocal<Boolean> currentTransactionReadOnly =
new NamedThreadLocal<>("Current transaction read-only status");
private static final ThreadLocal<Integer> currentTransactionIsolationLevel =
new NamedThreadLocal<>("Current transaction isolation level");
private static final ThreadLocal<Boolean> actualTransactionActive =
new NamedThreadLocal<>("Actual transaction active");
// 绑定资源到当前线程
public static void bindResource(Object key, Object value) throws IllegalStateException {
Map<Object, Object> map = resources.get();
if (map == null) {
map = new HashMap<>();
resources.set(map);
}
map.put(key, value);
}
// 从当前线程获取资源
public static Object getResource(Object key) {
Map<Object, Object> map = resources.get();
if (map == null) {
return null;
}
return map.get(key);
}
}
执行流程:
scss
// 1. 事务开始时
Connection con = dataSource.getConnection();
TransactionSynchronizationManager.bindResource(dataSource, con);
// 2. DAO操作获取连接时
public static Connection getConnection(DataSource dataSource) throws CannotGetJdbcConnectionException {
// 先尝试从ThreadLocal获取
ConnectionHolder conHolder = (ConnectionHolder)
TransactionSynchronizationManager.getResource(dataSource);
if (conHolder != null) {
return conHolder.getConnection(); // ✅ 返回事务连接
}
// 没有事务,新建连接
return dataSource.getConnection();
}
// 3. 事务结束时
TransactionSynchronizationManager.unbindResource(dataSource);
第八章:自调用失效的"终极揭秘" 🔍
现在你明白为什么自调用事务不生效了吗?
typescript
@Service
public class UserService {
public void outerMethod() {
// 直接调用内部方法
this.innerMethod(); // ❌ 事务不生效!
}
@Transactional
public void innerMethod() {
// 业务逻辑
}
}
原因:
- Spring事务基于AOP代理
- 只有通过代理对象 调用,才会被
TransactionInterceptor拦截 this.innerMethod()是目标对象内部调用,不会经过代理- 因此
TransactionInterceptor.invoke()不会执行
图解:
正常调用:Controller → 代理对象 → TransactionInterceptor → 目标对象
自调用:目标对象 → 目标对象(绕过了代理和拦截器!)
第九章:调试技巧------亲眼看看事务流转 🔬
9.1 开启调试日志
yaml
# application.yml
logging:
level:
org.springframework.transaction: DEBUG
org.springframework.jdbc.datasource.DataSourceTransactionManager: DEBUG
org.springframework.orm.jpa: DEBUG
9.2 观察日志输出
yaml
DEBUG o.s.j.d.DataSourceTransactionManager: Creating new transaction with name [com.example.UserService.saveUser]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT
DEBUG o.s.j.d.DataSourceTransactionManager: Acquired Connection [conn-id] for JDBC transaction
DEBUG o.s.j.d.DataSourceTransactionManager: Switching JDBC Connection [conn-id] to manual commit
DEBUG o.s.j.d.DataSourceTransactionManager: Initiating transaction commit
DEBUG o.s.j.d.DataSourceTransactionManager: Committing JDBC transaction on Connection [conn-id]
DEBUG o.s.j.d.DataSourceTransactionManager: Releasing JDBC Connection [conn-id] after transaction
9.3 在关键方法打断点
TransactionInterceptor.invoke()TransactionAspectSupport.invokeWithinTransaction()AbstractPlatformTransactionManager.getTransaction()DataSourceTransactionManager.doBegin()DataSourceTransactionManager.doCommit()/doRollback()
第十章:手写一个简化版事务管理器(理解原理) 🛠️
理解了原理,让我们手写一个极简版:
csharp
// 1. 事务管理器
public class SimpleTransactionManager {
private static ThreadLocal<Connection> connectionHolder = new ThreadLocal<>();
private static ThreadLocal<Boolean> transactionActive = ThreadLocal.withInitial(() -> false);
public static void begin() throws SQLException {
if (transactionActive.get()) {
return; // 已存在事务,支持传播
}
Connection conn = DataSourceUtils.getConnection();
conn.setAutoCommit(false); // 关键!
connectionHolder.set(conn);
transactionActive.set(true);
}
public static void commit() throws SQLException {
if (!transactionActive.get()) {
return;
}
Connection conn = connectionHolder.get();
conn.commit();
conn.setAutoCommit(true);
conn.close();
connectionHolder.remove();
transactionActive.set(false);
}
public static void rollback() throws SQLException {
if (!transactionActive.get()) {
return;
}
Connection conn = connectionHolder.get();
conn.rollback();
conn.setAutoCommit(true);
conn.close();
connectionHolder.remove();
transactionActive.set(false);
}
public static Connection getConnection() {
return connectionHolder.get();
}
}
// 2. 事务注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface SimpleTransactional {
Class<? extends Throwable>[] rollbackFor() default {RuntimeException.class};
}
// 3. 动态代理处理器
public class TransactionProxy implements InvocationHandler {
private Object target;
public TransactionProxy(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Method targetMethod = target.getClass().getMethod(method.getName(),
method.getParameterTypes());
// 检查是否有@SimpleTransactional注解
if (targetMethod.isAnnotationPresent(SimpleTransactional.class)) {
SimpleTransactional annotation = targetMethod.getAnnotation(SimpleTransactional.class);
try {
// 开启事务
SimpleTransactionManager.begin();
// 执行业务方法
Object result = method.invoke(target, args);
// 提交事务
SimpleTransactionManager.commit();
return result;
} catch (Throwable e) {
// 判断是否需要回滚
for (Class<? extends Throwable> rollbackEx : annotation.rollbackFor()) {
if (rollbackEx.isAssignableFrom(e.getClass())) {
SimpleTransactionManager.rollback();
break;
}
}
throw e;
}
} else {
return method.invoke(target, args);
}
}
}
总结:事务的完整生命周期 🌀
- 代理创建 :Spring容器启动时,为
@Transactional标注的Bean创建代理 - 方法调用 :通过代理调用方法,进入
TransactionInterceptor.invoke() - 获取属性 :解析
@Transactional注解的配置 - 决策事务:根据传播行为,决定新建、加入还是挂起事务
- 开启事务 :获取数据库连接,设置
autoCommit=false - 执行业务:调用原始业务方法
- 异常处理:根据异常类型决定回滚或提交
- 提交/回滚:提交事务或回滚事务
- 清理资源:关闭连接,清理ThreadLocal
最后的思考 🤔
通过源码分析,我们发现SpringBoot事务的本质是:
- 基于AOP的拦截
- 基于ThreadLocal的资源管理
- 基于JDBC Connection的autoCommit控制
理解了这些,你就能:
- 解释为什么自调用失效
- 理解传播行为的底层实现
- 知道事务同步管理器的工作原理
- 调试复杂的事务问题
- 甚至自己实现一个简单的事务框架
下次遇到事务问题,不要只是重启应用,打开调试日志,跟踪源码,你会发现每个异常背后,都有一个清晰的逻辑链。这就是从"会用框架"到"懂框架"的蜕变!🦋
源码如诗,每一行都藏着智慧。读懂了它,你就读懂了SpringBoot的灵魂。 📚
(现在,你可以自信地在团队分享:"我知道@Transactional的每一行代码在做什么!" 这种感觉,比加薪还棒!💰😄)