news 2026/4/16 9:19:49

Spring AOP场景4——事务管理(源码分析)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Spring AOP场景4——事务管理(源码分析)

在白嫖之前,希望你会内疚,最起码点个赞收藏再自取吧,源码在最后,自取;
在白嫖之前,希望你会内疚,最起码点个赞收藏再自取吧,源码在最后,自取;
在白嫖之前,希望你会内疚,最起码点个赞收藏再自取吧,源码在最后,自取;

本文从底层原理+核心代码角度,拆解AOP实现事务控制的完整逻辑,重点分析Spring事务管理器(PlatformTransactionManager)的核心实现,以及AOP如何通过环绕通知织入事务逻辑。所有代码均为可理解的核心简化版,保留Spring原生逻辑但剔除冗余,便于学习核心思路。

一、核心前置知识

1. 事务的本质(数据库层面)

事务的底层是数据库连接(java.sql.Connection)的特性:

  • 默认autoCommit=true:执行每条SQL后自动提交;
  • 开启事务:connection.setAutoCommit(false)
  • 提交:connection.commit()
  • 回滚:connection.rollback()

Spring事务的本质是通过AOP拦截方法,统一管理数据库连接的事务状态,让业务代码无需感知连接操作。

2. AOP实现事务的核心角色

角色作用
事务管理器(PlatformTransactionManager封装事务的开启/提交/回滚逻辑(对接数据库连接)
事务拦截器(TransactionInterceptorAOP环绕通知的核心实现,触发事务管理器操作
动态代理(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();}}}

手写版核心逻辑总结

  1. 注解标记:通过@MyTransactional标记需要事务的方法;
  2. AOP拦截:环绕通知拦截目标方法,触发事务逻辑;
  3. 事务管理器:封装数据库连接的autoCommitcommitrollback操作;
  4. 线程绑定:通过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存储当前线程的事务连接、事务状态,保证同线程内方法共用连接
传播行为处理支持REQUIREDREQUIRES_NEW等传播行为,灵活控制事务范围
异常兼容封装数据库异常为Spring统一的TransactionException,简化异常处理

四、AOP+事务管理器的完整执行流程(Spring原生)

结合前面的分析,梳理Spring中AOP实现事务的完整流程:

  1. 启动阶段
    • @EnableTransactionManagement开启事务注解驱动;
    • Spring扫描@Transactional注解,为目标类创建动态代理;
    • 注册TransactionInterceptor(事务拦截器,实现MethodInterceptor)。
  2. 运行阶段
  3. Controller调用业务方法 → 代理对象拦截方法调用;
  4. 触发TransactionInterceptor.invoke()
  5. 调用TransactionManager.getTransaction()开启事务;
  6. TransactionManager获取连接+关闭autoCommit
  7. 执行原始业务方法;
  8. 业务执行成功 →TransactionManager.commit()提交事务;
  9. 业务执行异常 →TransactionManager.rollback()回滚事务;
  10. 释放连接+恢复autoCommit
  11. 返回结果给Controller。

五、常见问题与核心注意点

  1. 事务失效的核心原因
    • 方法非public(AOP无法拦截非public方法);
    • 内部调用(代理对象无法拦截,如service.a()调用service.b()b()的事务失效);
    • 线程池异步调用(不同线程无法共享ThreadLocal中的连接);
    • 异常被捕获(未抛出到拦截器,无法触发回滚)。
  2. ThreadLocal的核心作用
    没有ThreadLocal,不同方法会获取不同的数据库连接,事务无法覆盖多个方法(这是事务管理的核心!)。
  3. 传播行为的本质
    传播行为是通过判断当前线程是否已有事务连接,决定“新建连接”或“复用连接”。

六、学习建议

  1. 先运行手写版代码,理解“注解+AOP+事务管理器+ThreadLocal”的核心;
  2. 阅读Spring源码:
    • 入口:TransactionInterceptor.invoke()
    • 核心类:DataSourceTransactionManagerTransactionSynchronizationManager
  3. 调试事务失效场景(如内部调用、异常捕获),加深对代理和线程绑定的理解。

总结

Spring中AOP实现事务管理的核心流程可总结为:首先通过@EnableTransactionManagement开启事务注解驱动,Spring扫描到业务方法上的@Transactional注解后,为目标业务类创建动态代理对象;当调用方触发标注了@Transactional的业务方法时,实际调用的是代理对象的方法,此时AOP的事务拦截器(TransactionInterceptor)会触发环绕通知逻辑——先调用事务管理器(如DataSourceTransactionManager)的getTransaction()方法,从数据源获取连接并通过ThreadLocal绑定到当前线程,关闭连接的自动提交以开启事务;接着执行原始的业务方法逻辑,若业务执行无异常,事务管理器调用commit()提交事务,若抛出符合回滚规则的异常,则调用rollback()回滚事务;最后无论提交或回滚,都会释放数据库连接、恢复连接的自动提交状态,并清空ThreadLocal中的事务信息,整个过程通过AOP的代理和环绕通知,将事务的开启、提交/回滚逻辑与业务代码解耦,保证业务方法的原子性。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/12 14:21:57

Codex效率命令文档生成:基于Anything-LLM提取函数说明

Codex效率命令文档生成&#xff1a;基于Anything-LLM提取函数说明 在现代软件开发中&#xff0c;一个看似不起眼却长期困扰团队的问题正变得愈发突出&#xff1a;代码写得飞快&#xff0c;文档却永远跟不上。你是否也经历过这样的场景&#xff1f;某个关键模块由前同事开发&…

作者头像 李华
网站建设 2026/4/8 19:26:07

Git下载TensorRT开源代码并编译为自定义镜像的方法

Git下载TensorRT开源代码并编译为自定义镜像的方法 在AI推理系统日益复杂的今天&#xff0c;一个常见的痛点是&#xff1a;官方发布的推理引擎无法支持新型算子&#xff0c;或者因安全合规要求无法直接使用闭源二进制包。比如某金融客户部署的模型中包含GroupNorm层&#xff0…

作者头像 李华
网站建设 2026/3/31 9:11:27

基于单片机的智能门锁控制系统设计(密码+指纹)【附代码】

&#x1f4c8; 算法与建模 | 专注PLC、单片机毕业设计 ✨ 擅长数据搜集与处理、建模仿真、程序设计、仿真代码、论文写作与指导&#xff0c;毕业论文、期刊论文经验交流。✅ 专业定制毕业设计✅ 具体问题可以私信或查看文章底部二维码在智能门锁控制系统的核心架构与微控制器选…

作者头像 李华
网站建设 2026/4/15 7:21:24

自定义你的无人机仿真测试场

最近和用户沟通时&#xff0c;我们反复听到这样的诉求&#xff1a; “能不能把我们厂区的真实布局搬进仿真里&#xff1f;” “我想用自己的无人机模型、障碍物&#xff0c;而不是只能依赖默认场景。”我们用一套完整的PrometheusSim(ProSim)示例工程给出答案。在保留官方预设场…

作者头像 李华
网站建设 2026/4/3 15:46:13

Qwen3-VL-8B微调实战:打造专属多模态AI

Qwen3-VL-8B微调实战&#xff1a;打造专属多模态AI 客户拍了一张老空调的照片发到客服窗口&#xff0c;问&#xff1a;“这台还能修吗&#xff1f;” 你希望AI能一眼看出这是台二十年前的窗式机&#xff0c;外壳锈迹斑斑&#xff0c;冷凝管变形&#xff0c;然后告诉你&#xff…

作者头像 李华
网站建设 2026/4/10 0:07:11

vLLM多模态输入:图像、视频与音频处理全解析

vLLM 多模态输入&#xff1a;图像、视频与音频处理全解析 在生成式 AI 快速演进的今天&#xff0c;单一文本推理已无法满足复杂应用场景的需求。从智能客服中的图文问答&#xff0c;到教育平台上的音视频内容理解&#xff0c;再到工业质检中的视觉分析——多模态能力正成为大模…

作者头像 李华