在白嫖之前,希望你会内疚,最起码点个赞收藏再自取吧,源码在最后,自取;
在白嫖之前,希望你会内疚,最起码点个赞收藏再自取吧,源码在最后,自取;
在白嫖之前,希望你会内疚,最起码点个赞收藏再自取吧,源码在最后,自取;
本文从底层原理+核心代码角度,拆解AOP实现事务控制的完整逻辑,重点分析Spring事务管理器(PlatformTransactionManager)的核心实现,以及AOP如何通过环绕通知织入事务逻辑。所有代码均为可理解的核心简化版,保留Spring原生逻辑但剔除冗余,便于学习核心思路。
一、核心前置知识
1. 事务的本质(数据库层面)
事务的底层是数据库连接(java.sql.Connection)的特性:
- 默认
autoCommit=true:执行每条SQL后自动提交; - 开启事务:
connection.setAutoCommit(false); - 提交:
connection.commit(); - 回滚:
connection.rollback()。
Spring事务的本质是通过AOP拦截方法,统一管理数据库连接的事务状态,让业务代码无需感知连接操作。
2. AOP实现事务的核心角色
| 角色 | 作用 |
|---|---|
事务管理器(PlatformTransactionManager) | 封装事务的开启/提交/回滚逻辑(对接数据库连接) |
事务拦截器(TransactionInterceptor) | AOP环绕通知的核心实现,触发事务管理器操作 |
| 动态代理(JDK/CGLIB) | 为业务类生成代理对象,接管方法调用 |
事务注解(@Transactional) | 标记需要事务增强的方法,定义事务属性(传播行为、隔离级别等) |
二、手写简化版AOP事务框架(理解底层)
先通过手写核心代码模拟Spring事务的实现逻辑,掌握AOP+事务的核心思路。
步骤1:定义事务注解(模拟@Transactional)
importjava.lang.annotation.*;/** * 自定义事务注解,标记需要事务控制的方法 */@Target({ElementType.METHOD})@Retention(RetentionPolicy.RUNTIME)@Documentedpublic@interfaceMyTransactional{// 模拟事务传播行为(简化版)Propagationpropagation()defaultPropagation.REQUIRED;// 事务隔离级别(简化版)Isolationisolation()defaultIsolation.DEFAULT;// 异常回滚规则Class<?extendsThrowable>[]rollbackFor()default{Exception.class};}// 传播行为枚举(简化)enumPropagation{REQUIRED// 默认:有事务则加入,无则新建}// 隔离级别枚举(简化)enumIsolation{DEFAULT// 使用数据库默认隔离级别}步骤2:实现事务管理器(模拟DataSourceTransactionManager)
importorg.springframework.jdbc.datasource.DataSourceUtils;importjavax.sql.DataSource;importjava.sql.Connection;importjava.sql.SQLException;/** * 自定义事务管理器:封装数据库连接的事务操作 * 核心:绑定连接到当前线程(ThreadLocal),保证同线程内方法共用一个连接 */publicclassMyTransactionManager{// 数据源(Spring中通过配置注入)privatefinalDataSourcedataSource;// 线程本地变量:存储当前线程的事务连接+状态privatefinalThreadLocal<TransactionInfo>threadLocal=newThreadLocal<>();publicMyTransactionManager(DataSourcedataSource){this.dataSource=dataSource;}/** * 开启事务 */publicTransactionInfobegin(MyTransactionalannotation){// 1. 获取数据库连接(Spring中通过DataSourceUtils保证线程绑定)Connectionconn=DataSourceUtils.getConnection(dataSource);TransactionInfotxInfo=newTransactionInfo();txInfo.setConn(conn);txInfo.setAnnotation(annotation);txInfo.setOldAutoCommit(true);// 保存原有autoCommit状态try{// 2. 关闭自动提交,开启事务if(conn.getAutoCommit()){conn.setAutoCommit(false);txInfo.setOldAutoCommit(true);}// 3. 设置隔离级别(简化版)if(annotation.isolation()!=Isolation.DEFAULT){conn.setTransactionIsolation(annotation.isolation().ordinal()+1);}// 4. 将事务信息绑定到当前线程threadLocal.set(txInfo);returntxInfo;}catch(SQLExceptione){thrownewRuntimeException("开启事务失败",e);}}/** * 提交事务 */publicvoidcommit(TransactionInfotxInfo){if(txInfo==null)return;Connectionconn=txInfo.getConn();try{if(conn!=null&&!conn.isClosed()){conn.commit();// 提交事务// 恢复原有autoCommit状态conn.setAutoCommit(txInfo.isOldAutoCommit());}}catch(SQLExceptione){thrownewRuntimeException("提交事务失败",e);}finally{// 释放连接+清空线程变量DataSourceUtils.releaseConnection(conn,dataSource);threadLocal.remove();}}/** * 回滚事务 */publicvoidrollback(TransactionInfotxInfo){if(txInfo==null)return;Connectionconn=txInfo.getConn();try{if(conn!=null&&!conn.isClosed()){conn.rollback();// 回滚事务conn.setAutoCommit(txInfo.isOldAutoCommit());}}catch(SQLExceptione){thrownewRuntimeException("回滚事务失败",e);}finally{DataSourceUtils.releaseConnection(conn,dataSource);threadLocal.remove();}}// 事务信息封装类publicstaticclassTransactionInfo{privateConnectionconn;privateMyTransactionalannotation;privatebooleanoldAutoCommit;// getter/setter 省略}}步骤3:实现AOP环绕通知(事务拦截器)
importorg.aspectj.lang.ProceedingJoinPoint;importorg.aspectj.lang.annotation.Around;importorg.aspectj.lang.annotation.Aspect;importorg.aspectj.lang.reflect.MethodSignature;importjava.lang.reflect.Method;/** * 自定义事务拦截器:AOP环绕通知核心逻辑 * 作用:拦截@MyTransactional注解的方法,织入事务开启/提交/回滚逻辑 */@AspectpublicclassMyTransactionInterceptor{// 事务管理器(Spring中通过依赖注入)privatefinalMyTransactionManagertransactionManager;publicMyTransactionInterceptor(MyTransactionManagertransactionManager){this.transactionManager=transactionManager;}/** * 环绕通知:拦截所有标注@MyTransactional的方法 */@Around("@annotation(com.example.MyTransactional)")publicObjectintercept(ProceedingJoinPointjoinPoint)throwsThrowable{// 1. 获取方法上的事务注解MethodSignaturesignature=(MethodSignature)joinPoint.getSignature();Methodmethod=signature.getMethod();MyTransactionalannotation=method.getAnnotation(MyTransactional.class);MyTransactionManager.TransactionInfotxInfo=null;try{// 2. 开启事务txInfo=transactionManager.begin(annotation);// 3. 执行原始业务方法(核心:调用目标方法)Objectresult=joinPoint.proceed();// 4. 提交事务transactionManager.commit(txInfo);returnresult;}catch(Throwablee){// 5. 异常回滚(判断是否符合回滚规则)if(isRollback(e,annotation.rollbackFor())){transactionManager.rollback(txInfo);}throwe;// 抛出异常,上层可感知}}/** * 判断异常是否需要回滚 */privatebooleanisRollback(Throwablee,Class<?extendsThrowable>[]rollbackFor){for(Class<?extendsThrowable>clazz:rollbackFor){if(clazz.isInstance(e)){returntrue;}}returnfalse;}}步骤4:配置类(开启AOP+注入组件)
importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Configuration;importorg.springframework.context.annotation.EnableAspectJAutoProxy;importorg.springframework.jdbc.datasource.DriverManagerDataSource;importjavax.sql.DataSource;/** * 配置类:组装AOP事务的核心组件 */@Configuration@EnableAspectJAutoProxy// 开启AOP动态代理publicclassTransactionConfig{// 1. 配置数据源@BeanpublicDataSourcedataSource(){DriverManagerDataSourcedataSource=newDriverManagerDataSource();dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");dataSource.setUrl("jdbc:mysql://localhost:3306/test?useSSL=false");dataSource.setUsername("root");dataSource.setPassword("123456");returndataSource;}// 2. 配置自定义事务管理器@BeanpublicMyTransactionManagermyTransactionManager(DataSourcedataSource){returnnewMyTransactionManager(dataSource);}// 3. 配置事务拦截器(AOP切面)@BeanpublicMyTransactionInterceptormyTransactionInterceptor(MyTransactionManagertransactionManager){returnnewMyTransactionInterceptor(transactionManager);}}步骤5:业务层使用自定义事务注解
importorg.springframework.stereotype.Service;importjavax.annotation.Resource;importjava.sql.Connection;importjava.sql.PreparedStatement;importjava.sql.SQLException;@ServicepublicclassOrderService{@ResourceprivateDataSourcedataSource;/** * 标记需要事务控制的业务方法 */@MyTransactional(rollbackFor={Exception.class})publicvoidcreateOrder(LongproductId,Integernum)throwsSQLException{// 业务逻辑1:扣减库存deductStock(productId,num);// 业务逻辑2:创建订单(模拟异常:如果num>10则抛异常,触发回滚)if(num>10){thrownewRuntimeException("库存超出限制");}createOrderRecord(productId,num);}// 扣减库存privatevoiddeductStock(LongproductId,Integernum)throwsSQLException{Stringsql="UPDATE stock SET num = num - ? WHERE product_id = ?";try(Connectionconn=dataSource.getConnection();PreparedStatementps=conn.prepareStatement(sql)){ps.setInt(1,num);ps.setLong(2,productId);ps.executeUpdate();}}// 创建订单记录privatevoidcreateOrderRecord(LongproductId,Integernum)throwsSQLException{Stringsql="INSERT INTO `order` (product_id, num) VALUES (?, ?)";try(Connectionconn=dataSource.getConnection();PreparedStatementps=conn.prepareStatement(sql)){ps.setLong(1,productId);ps.setInt(2,num);ps.executeUpdate();}}}手写版核心逻辑总结
- 注解标记:通过
@MyTransactional标记需要事务的方法; - AOP拦截:环绕通知拦截目标方法,触发事务逻辑;
- 事务管理器:封装数据库连接的
autoCommit、commit、rollback操作; - 线程绑定:通过
ThreadLocal保证同线程内的业务方法共用一个数据库连接(核心!否则多方法会用不同连接,事务失效)。
三、Spring原生事务管理器深度解析
Spring的PlatformTransactionManager是事务管理的核心接口,我们基于手写版对比,分析其原生实现。
1. 核心接口体系
// Spring事务管理器顶级接口publicinterfacePlatformTransactionManager{// 获取事务(开启事务)TransactionStatusgetTransaction(TransactionDefinitiondefinition)throwsTransactionException;// 提交事务voidcommit(TransactionStatusstatus)throwsTransactionException;// 回滚事务voidrollback(TransactionStatusstatus)throwsTransactionException;}// 事务定义(传播行为、隔离级别、超时时间等)publicinterfaceTransactionDefinition{intPROPAGATION_REQUIRED=0;// 默认传播行为intISOLATION_DEFAULT=-1;// 默认隔离级别// 省略其他常量+方法}// 事务状态(封装事务的连接、是否新建、是否回滚等)publicinterfaceTransactionStatusextendsSavepointManager{booleanisNewTransaction();// 是否是新建事务booleanhasSavepoint();// 是否有保存点voidsetRollbackOnly();// 标记为回滚booleanisRollbackOnly();// 是否需要回滚voidflush();// 刷新事务booleanisCompleted();// 事务是否完成}2. 核心实现类:DataSourceTransactionManager
DataSourceTransactionManager是JDBC/MyBatis场景下的核心实现,核心方法拆解:
(1)开启事务:getTransaction()
@OverridepublicTransactionStatusgetTransaction(TransactionDefinitiondefinition)throwsTransactionException{// 1. 获取事务定义(传播行为、隔离级别等)TransactionDefinitiondef=(definition!=null?definition:TransactionDefinition.withDefaults());// 2. 获取数据源连接(绑定到当前线程)Objecttransaction=doGetTransaction();booleandebugEnabled=logger.isDebugEnabled();// 3. 处理传播行为(核心:判断是否新建事务/加入已有事务)if(def.getPropagationBehavior()==TransactionDefinition.PROPAGATION_REQUIRED){// 检查当前线程是否已有事务if(isExistingTransaction(transaction)){// 有事务则加入(复用连接)returnhandleExistingTransaction(def,transaction,debugEnabled);}// 无事务则新建if(def.getTimeout()<TransactionDefinition.TIMEOUT_DEFAULT){thrownewInvalidTimeoutException("Invalid transaction timeout",def.getTimeout());}// 4. 开启新事务(核心:获取连接+关闭autoCommit)returnstartNewTransaction(def,transaction,debugEnabled);}// 省略其他传播行为的处理...}// 核心:开启新事务privateTransactionStatusstartNewTransaction(TransactionDefinitiondefinition,Objecttransaction,booleandebugEnabled){DataSourceTransactionObjecttxObject=(DataSourceTransactionObject)transaction;// 5. 获取数据库连接(通过DataSourceUtils,保证线程绑定)Connectionconn=DataSourceUtils.getConnection(obtainDataSource());txObject.setConnectionHolder(newConnectionHolder(conn),true);// 6. 关闭自动提交,开启事务try{if(conn.getAutoCommit()){txObject.setMustRestoreAutoCommit(true);if(debugEnabled){logger.debug("Switching JDBC Connection ["+conn+"] to manual commit");}conn.setAutoCommit(false);}// 7. 设置隔离级别prepareTransactionalConnection(conn,definition);// 8. 标记事务为新建txObject.setNewTransaction(true);if(definition.isReadOnly()){txObject.setReadOnly(true);}// 9. 返回事务状态returnnewDefaultTransactionStatus(txObject,true,false,definition.isReadOnly(),debugEnabled,null);}catch(SQLExceptionex){DataSourceUtils.releaseConnection(conn,obtainDataSource());thrownewCannotCreateTransactionException("Could not open JDBC Connection for transaction",ex);}}(2)提交事务:commit()
@Overridepublicvoidcommit(TransactionStatusstatus)throwsTransactionException{DefaultTransactionStatusdefStatus=(DefaultTransactionStatus)status;// 1. 如果已标记回滚,则直接回滚if(defStatus.isRollbackOnly()){processRollback(defStatus,false);return;}// 2. 非新建事务则不提交(交给外层事务处理)if(!defStatus.isNewTransaction()){if(defStatus.hasTransaction()){if(defStatus.isDebug()){logger.debug("Not committing JDBC transaction because it's not a new transaction");}}return;}// 3. 新建事务则提交try{doCommit(defStatus);}catch(SQLExceptionex){thrownewTransactionSystemException("Could not commit JDBC transaction",ex);}finally{// 4. 释放连接+恢复autoCommitcleanupAfterCompletion(defStatus.getTransaction());}}// 实际提交逻辑protectedvoiddoCommit(DefaultTransactionStatusstatus){DataSourceTransactionObjecttxObject=(DataSourceTransactionObject)status.getTransaction();Connectioncon=txObject.getConnectionHolder().getConnection();if(status.isDebug()){logger.debug("Committing JDBC transaction on Connection ["+con+"]");}try{con.commit();// 数据库层面提交}catch(SQLExceptionex){thrownewTransactionSystemException("Could not commit JDBC transaction",ex);}}(3)回滚事务:rollback()
@Overridepublicvoidrollback(TransactionStatusstatus)throwsTransactionException{DefaultTransactionStatusdefStatus=(DefaultTransactionStatus)status;// 1. 非新建事务则标记回滚(交给外层处理)if(!defStatus.isNewTransaction()){if(defStatus.hasTransaction()){if(defStatus.isDebug()){logger.debug("Setting JDBC transaction rollback-only");}defStatus.setRollbackOnly();}return;}// 2. 新建事务则直接回滚processRollback(defStatus,false);}// 实际回滚逻辑privatevoidprocessRollback(DefaultTransactionStatusstatus,booleanunexpected){try{booleanrollback=true;// 处理保存点(简化版忽略)if(status.hasSavepoint()){if(status.isDebug()){logger.debug("Rolling back JDBC transaction to savepoint");}status.rollbackToSavepoint();rollback=false;}// 3. 回滚事务if(rollback){doRollback(status);}}catch(SQLExceptionex){thrownewTransactionSystemException("Could not roll back JDBC transaction",ex);}finally{// 4. 释放连接+恢复autoCommitcleanupAfterCompletion(status.getTransaction());}}protectedvoiddoRollback(DefaultTransactionStatusstatus){DataSourceTransactionObjecttxObject=(DataSourceTransactionObject)status.getTransaction();Connectioncon=txObject.getConnectionHolder().getConnection();if(status.isDebug()){logger.debug("Rolling back JDBC transaction on Connection ["+con+"]");}try{con.rollback();// 数据库层面回滚}catch(SQLExceptionex){thrownewTransactionSystemException("Could not roll back JDBC transaction",ex);}}3. Spring事务管理器核心设计思路
| 设计点 | 作用 |
|---|---|
接口抽象(PlatformTransactionManager) | 解耦事务逻辑与具体数据库类型(支持JDBC、JPA、Hibernate等) |
线程绑定(TransactionSynchronizationManager) | 通过ThreadLocal存储当前线程的事务连接、事务状态,保证同线程内方法共用连接 |
| 传播行为处理 | 支持REQUIRED、REQUIRES_NEW等传播行为,灵活控制事务范围 |
| 异常兼容 | 封装数据库异常为Spring统一的TransactionException,简化异常处理 |
四、AOP+事务管理器的完整执行流程(Spring原生)
结合前面的分析,梳理Spring中AOP实现事务的完整流程:
- 启动阶段:
@EnableTransactionManagement开启事务注解驱动;- Spring扫描
@Transactional注解,为目标类创建动态代理; - 注册
TransactionInterceptor(事务拦截器,实现MethodInterceptor)。
- 运行阶段:
- Controller调用业务方法 → 代理对象拦截方法调用;
- 触发
TransactionInterceptor.invoke(); - 调用
TransactionManager.getTransaction()开启事务; TransactionManager获取连接+关闭autoCommit;- 执行原始业务方法;
- 业务执行成功 →
TransactionManager.commit()提交事务; - 业务执行异常 →
TransactionManager.rollback()回滚事务; - 释放连接+恢复
autoCommit; - 返回结果给Controller。
五、常见问题与核心注意点
- 事务失效的核心原因:
- 方法非public(AOP无法拦截非public方法);
- 内部调用(代理对象无法拦截,如
service.a()调用service.b(),b()的事务失效); - 线程池异步调用(不同线程无法共享
ThreadLocal中的连接); - 异常被捕获(未抛出到拦截器,无法触发回滚)。
- ThreadLocal的核心作用:
没有ThreadLocal,不同方法会获取不同的数据库连接,事务无法覆盖多个方法(这是事务管理的核心!)。 - 传播行为的本质:
传播行为是通过判断当前线程是否已有事务连接,决定“新建连接”或“复用连接”。
六、学习建议
- 先运行手写版代码,理解“注解+AOP+事务管理器+ThreadLocal”的核心;
- 阅读Spring源码:
- 入口:
TransactionInterceptor.invoke(); - 核心类:
DataSourceTransactionManager、TransactionSynchronizationManager;
- 入口:
- 调试事务失效场景(如内部调用、异常捕获),加深对代理和线程绑定的理解。
总结
Spring中AOP实现事务管理的核心流程可总结为:首先通过@EnableTransactionManagement开启事务注解驱动,Spring扫描到业务方法上的@Transactional注解后,为目标业务类创建动态代理对象;当调用方触发标注了@Transactional的业务方法时,实际调用的是代理对象的方法,此时AOP的事务拦截器(TransactionInterceptor)会触发环绕通知逻辑——先调用事务管理器(如DataSourceTransactionManager)的getTransaction()方法,从数据源获取连接并通过ThreadLocal绑定到当前线程,关闭连接的自动提交以开启事务;接着执行原始的业务方法逻辑,若业务执行无异常,事务管理器调用commit()提交事务,若抛出符合回滚规则的异常,则调用rollback()回滚事务;最后无论提交或回滚,都会释放数据库连接、恢复连接的自动提交状态,并清空ThreadLocal中的事务信息,整个过程通过AOP的代理和环绕通知,将事务的开启、提交/回滚逻辑与业务代码解耦,保证业务方法的原子性。