开发者

Spring声明式事务管理从原理到实战示例

目录
  • 一、什么是声明式事务管理?
    • ✅ 简单说:
    • 对比:编程式 vs 声明式
  • 二、声明式事务是如何实现的?(核心原理)
    • 工作流程如下:
    • ️ 关键组件:
  • 三、如何配置声明式事务?(XML 配置方式)
    • 示例配置解析:
    • 关键点:
  • 四、事务回滚机制(Rollback Rules)
    • 默认规则:
    • 自定义回滚规则:
      • 1. 某个检查型异常也要回滚:
      • 2. 某个运行时异常不要回滚:
      • 3. 多规则优先级:
  • 五、响应式事务(Reactive Transaction Management)
    • 关键区别:
    • ️ 六、不同 Bean 使用不同事务配置
      • 示例:
      • 七、<tx:method>的所有配置项总结
        • 八、重要注意事项
          • ✅ 总结:如何理解这段内容?
            • 建议学习路径

              一、什么是声明式事务管理?

              ✅ 简单说:

              你不用在代码里手动写 beginTransaction()commit()rollback(),而是通过配置或注解来告诉 Spring:“这个方法需要事务”,Spring 自动帮你管理事务的开始、提交或回滚。

              对比:编程式 vs 声明式

              类型特点代码侵入性
              编程式事务手动控制事务(如使用 TransactionTemplate高(代码里到处是事务逻辑)
              声明式事务用配置或注解声明事务行为低(业务代码干净)

              Spring 推荐使用 声明式事务,因为它更符合“轻量级容器”的理念 —— 业务代码不依赖事务框架。

              二、声明式事务是如何实现的?(核心原理)

              Spring 的声明式事务是基于 AOP(面向切面编程) 实现的。

              工作流程如下:

              1. 你有一个服务类,比如 DefaultFooService
              2. 你在配置中声明了哪些方法需要事务(通过 <tx:advice>@Transactional)。
              3. Spring 在启动时,会为这个类创建一个 代理对象(Proxy)
              4. 当你调用 fooService.insertFoo(...) 时,实际上是调用了代理对象的方法。
              5. 代理对象在方法执行前开启事务,执行后根据结果决定提交或回滚。
              你调用:   fooService.insertFoo()
                      ↓
              实际执行:  Proxy → 开启事务 → 调用真实方法 → 成功则提交,异常则回滚
              

              ️ 关键组件:

              • TransactionInterceptor:事务拦截器,负责在方法前后插入事务逻辑。
              • TransactionManager:事务管理器,真正执行开启、提交、回滚操作(如 DataSourceTransactionManager)。
              • AOP 代理:JDK 动态代理 或 CGLIB,用于织入事务逻辑。

              三、如何配置声明式事务?(XML 配置方式)

              文档中的例子使用 XML 配置,虽然现在更多用注解,但理解 XML 有助于理解底层机制。

              示例配置解析:

              <!-- 定义数据源 -->
              <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"> ... </bean>
              <!-- 定义事务管理器 -->
              <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
                  <property name="dataSource" ref="dataSource"/>
              </bean>
              <!-- 定义事务通知(规则) -->
              <tx:advice id="txAdvice" transaction-manager="txManager">
                  <tx:attributes>
                      <tx:method njsame="get*" read-only="true"/>  <!-- 所有get开头的方法:只读事务 -->
                      <tx:method name="*" />                     <!-- 其他方法:默认事务(读写) -->
                  </tx:attributes>
              </tx:advice>
              <!-- 将事务通知应用到指定的切点 -->
              <aop:config>
                  <!-- 切点:匹配 FooService 接口的所有方法 -->
               javascript   <aop:pointcut id="fooServiceOperation" 
                                expression="execution(* x.y.service.FooService.*(..))"/>
                  <!-- 绑定通知和切点 -->
                  <aop:advisor advice-ref="txAdvice" pointcut-ref="fooServiceOperation"/>
              </aop:config>

              关键点:

              • tx:method name="get*":所有以 get 开头的方法使用 只读事务(性能优化)。
              • tx:method name="*":其他方法使用默认事务(读写)。
              • aop:pointcut 使用 ASPectJ 表达式 匹配方法。

              四、事务回滚机制(Rollback Rules)

              这是 Spring 事务的一大亮点:你可以精确控制哪些异常触发回滚。

              默认规则:

              • 运行时异常(RuntimeException):自动回滚(如 NullPointerExceptionIllegalArgumentException
              • 检查型异常(Checked Exception)不回滚(如 IOException、自定义的 MyException

              ⚠️ 这与 EJB CMT 不同!EJB 中检查型异常也不回滚,但 Spring 允许你自定义。

              自定义回滚规则:

              1. 某个检查型异常也要回滚:

              <tx:method name="updateStock" rollback-for="NoProductInStockException"/>
              

              2. 某个运行时异常不要回滚:

              <tx:method name="updateStock" no-rollback-for="InstrumentNotFoundException"/>
              

              3. 多规则优先级:

              <tx:method name="*" 
                         rollback-for="Throwable" 
                         no-rollback-for="InstrumentNotFoundException"/>
              

              ✅ 所有异常都回滚,除了 InstrumentNotFoundException

              五、响应式事务(Reactive Transaction Management)

              Spring 5+ 支持响应式编程(如 WebFlux),事务也支持响应式。

              关键区别:

              特性传统(Imppythonerative)响应式(Reactive)
              返回类型Foo, voidMono<Foo>, Flux<Foo>
              事务管理器PlatformTransactionManagerReactiveTransactionManager
              事务传播基于 ThreadLocal基于 Reactor Context
              事务触发方法调用立即开始返回的 Publisher 被订阅时才开始

              响应式事务是“惰性的”:调用方法不立即开启事务,而是等到 .subscribe() 时才开始。

              ️ 六、不同 Bean 使用不同事务配置

              你可以为不同的服务类设置不同的事务规则。

              示例:

              <aop:pointcut id="defaultServiceOperation" 
                            expression="execution(* x.y.service.*Service.*(..))"/>
              <aop:pointcut id="noTxServiceOperation" 
                            expression="execution(* x.y.service.ddl.DefaultDdlManager.*(..))"/>
              <aop:advisor pointcut-ref="defaultServiceOperation" advice-ref="defaultTxAdvice"/>
              <aop:advisor pointcut-ref="noTxServiceOperation" advice-ref="noTxAdvice"/>
              • *Service 类:使用默认事务(可读写)
              • DefaultDdlManager 类:使用 propagation="NEVER"(禁止在事务中运行)

              这很实用,比如 DDL 操作(建表、删表)通常不应在事务中运行。

              七、<tx:method>的所有配置项总结

              属性是否必需默认值说明
              name✅ 是-方法名(支持 * 通配符)
              propagationREQUIRED传播行为(如 REQUIRED, REQUIRES_NEW, NEVER 等)
              isolationDEFAULT隔离级别(如 READ_COMMITTED
              timeout-1(无超时)超时时间(秒)
              read-onlyfalse是否只读事务
              rollback-for-哪些异常触发回滚(可写多个,逗号分隔)
              no-rollback-for-哪些异常触发回滚

              八、重要注意事项

              • 代理机制限制
                • 只有 外部调用 代理对象的方法才会触发事务。
                • 如果你在同一个类http://www.devze.com中调用 this.method()事务不会生效(因为没走代理)。
              • 事务不会跨远程调用
                • Spring 不支持像 EJB 那样将事务上下文传播到远程服务。
                • 如果你需要分布式事务,考虑使用 SeataSpring Cloud Alibaba 等方案。
              • 异常必须抛出
                • 如果你在方法内部 catwww.devze.comch 了异常但没有重新抛出,事务不会回滚
                • 正确做法:catchthrow 或调用 setRollbackOnly()
              • @Transactional 注解更常用
                • 现代 Spring 开发通常使用 @Transactional 注解代替 XML。
              • 例如:
              @Service
              public class FooService {
                  @Transactional(readOnly = true)
                  public Foo getFoo(String name) { ... }
                  @Transactional(rollbackFor = MyException.class)
                  public void updateFoo(Foo foo) { ... }
              }

              需要启用:@EnableTransactionManagement

              ✅ 总结:如何理解这段内容?

              问题回答
              声明式事务是什么?用配置或注解声明事务,无需手动控制。
              怎么实现的?基于 AOP,Spring 创建代理对象,在方法前后自动加事务逻辑。
              怎么配置?<tx:advice> 定义规则,用 <aop:config> 应用到目标方法。
              异常怎么回滚?默认运行时异常回滚,可通过 rollback-for 自定义。
              不同类不同配置?可以,定义多个 <tx:advice><aop:advisor>
              响应式支持吗?支持,基于 ReactiveTransactionManager 和 Reactor 上下文。

              建议学习路径

              1. 先理解 AOP 基本概念(代理、切点、通知)
              2. 动手写一个 XML 配置的声明式事务例子
              3. 改造成 @Transactional 注解方式
              4. 尝试 自定义回滚规则
              5. 了解 事务传播行为(如 REQUIRED, REQUIRES_NEW
              6. (进阶)学习 响应式事务分布式事务

              如果你希望,我可以:

              • 把这个内容转成中文思维导图
              • 写一个完整的可运行代码示例(Java + Spring + 注解)
              • 解释 @Transactional 的各种传播行为

              欢迎继续提问!

              到此这篇关于Spring声明式事务管理从原理到实战示例的文章就介绍到这了,更多相关Spring声明式事务管理内容请搜索编程客栈(www.devze.com)以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程客栈(www.devze.com)!

              0

              上一篇:

              下一篇:

              精彩评论

              暂无评论...
              验证码 换一张
              取 消

              最新开发

              开发排行榜