当前位置: 首页 > news >正文

Spring 事务传播和自调用行为

为了方便讲解,这里的A、B、C类都是Spring管理的Bean。

自调用行为

自调用行为示例

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;
​
@Component
public class B {@Autowiredpublic void b() {this.c();}@Transactionalpublic void c() {
​}
}

不生效的原因

代码示例 B.b() 直接调用 B.c() 是一个典型的自调用情况。在这种情况下,即使 B.c() 方法有 @Transactional 注解,由于是在同一个类的内部直接调用,事务注解不会被 Spring 的代理机制捕获,因此不会生效。

在 Spring 的 AOP(面向切面编程)架构中,事务管理是通过代理(Proxy)来实现的。当一个方法被调用时,如果这个方法从外部(即通过 Spring 容器管理的 Bean)调用,并且配置了 @Transactional,Spring 会通过代理来拦截这个调用,然后根据 @Transactional 的属性来开始、加入、挂起或结束事务。但如果这个调用是从同一个类的内部发生的,比如一个方法直接调用同一个类中的另一个方法,这种调用就不会经过代理,Spring 无法施加事务管理的逻辑。

自调用行为解决方案

通过 Spring ApplicationContext 获取代理

可以让 Spring 注入自身的 ApplicationContext,并使用它来获取当前 Bean 的代理,然后通过代理来调用方法。

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;
​
@Component
public class B {@Autowiredprivate ApplicationContext applicationContext;
​public void b() {B b = applicationContext.getBean(B.class);b.c();}
​public void c() {// Transactional code}
}
使用 AopContext.currentProxy()

这是一个更简单的方式,但需要在 Spring 配置中启用 exposeProxy=true。然后你可以通过 AopContext.currentProxy() 来获取当前对象的代理并进行调用。

要启用 exposeProxy,需要在 Spring 的配置中设置:

@EnableAspectJAutoProxy(exposeProxy = true)
import org.springframework.aop.framework.AopContext;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
​
@Component
public class B {public void b() {((B) AopContext.currentProxy()).c();}
​@Transactionalpublic void c() {// Transactional code}
}

正确的事务传播行为

2. 创建三个Bean类

接下来,我们创建三个类,每个类都有不同的方法,演示事务的传播:

A类
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
​
@Service
public class A {@Autowiredprivate B b;
​@Transactionalpublic void methodA() {System.out.println("Inside A.methodA");b.methodB();}
}
B类
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
​
@Service
public class B {@Autowiredprivate C c;
​@Transactionalpublic void methodB() {System.out.println("Inside B.methodB");c.methodC();}
}
C类
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
​
@Service
public class C {
​@Transactionalpublic void methodC() {System.out.println("Inside C.methodC");// 这里可以添加实际的数据库操作代码}
}

解释

在这个设置中:

  • 当 methodA 被调用时,它在 A 类的事务环境中开始执行。

  • A.methodA 调用 B.methodB,B.methodB 进一步调用 C.methodC。由于每个方法都通过Spring的代理调用,每个方法都有 @Transactional 注解,这保证了事务在整个调用链中得以正确管理。

  • 如果有需要,每个方法可以根据其事务传播设置独立地控制事务行为。在这个示例中,我们没有明确设置传播行为,所以它们默认使用 Propagation.REQUIRED,这意味着它们会加入到现有的事务中。

为什么这里的methodB没有明写事务,但是methodA、methodB、methodC都有事务

因为A.methodA事务传播到B.methodB,B.methodB传播到C.methodC,因为B.methodB调用C.methodC不属于自调用,所以Spring能捕获到并且进行添加事务。

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • python打包 exe 提示no module named flask
  • 【记忆回溯】【深度搜索】【动态规划】【字符串】【力扣】单词拆分
  • pandas操作Excel文件
  • react vant 在使用dialog.confirm取消报错 Uncaught (in promise) undefined
  • jQuery入门(七)jQuery实现按钮分页
  • 关于VUE3开发频繁引入ref,reactive,computed等基础函数。
  • c++ 标准模板库 STL
  • 运维问题0001:MM模块-MIGO收货报错“消息号 M7036 对于采购订单********无收货可能”
  • 【MySql】在Redis使用中,缓存不一致的夺命十八问!
  • 系统监控和命令行环境
  • 会赢的!(牛客)
  • python进阶篇-day04-闭包与装饰器
  • Springboot快速创建的两种方法(简单易学)
  • UE5 UMG UI编辑器工作流
  • HarmonyOS NEXT未成年人模式无缝联动所有应用,过滤非适龄内容
  • [译] React v16.8: 含有Hooks的版本
  • [译]如何构建服务器端web组件,为何要构建?
  • Django 博客开发教程 8 - 博客文章详情页
  • ECMAScript 6 学习之路 ( 四 ) String 字符串扩展
  • Java|序列化异常StreamCorruptedException的解决方法
  • php ci框架整合银盛支付
  • React的组件模式
  • springMvc学习笔记(2)
  • vue2.0开发聊天程序(四) 完整体验一次Vue开发(下)
  • vue--为什么data属性必须是一个函数
  • 从输入URL到页面加载发生了什么
  • 关于extract.autodesk.io的一些说明
  • 规范化安全开发 KOA 手脚架
  • 码农张的Bug人生 - 初来乍到
  • 深度解析利用ES6进行Promise封装总结
  • 吐槽Javascript系列二:数组中的splice和slice方法
  • 异常机制详解
  • 原生 js 实现移动端 Touch 滑动反弹
  • 职业生涯 一个六年开发经验的女程序员的心声。
  • 数据可视化之下发图实践
  • ​queue --- 一个同步的队列类​
  • ​TypeScript都不会用,也敢说会前端?
  • # centos7下FFmpeg环境部署记录
  • # 安徽锐锋科技IDMS系统简介
  • #pragma 指令
  • (4)通过调用hadoop的java api实现本地文件上传到hadoop文件系统上
  • (TOJ2804)Even? Odd?
  • (附源码)spring boot智能服药提醒app 毕业设计 102151
  • (附源码)ssm智慧社区管理系统 毕业设计 101635
  • (机器学习的矩阵)(向量、矩阵与多元线性回归)
  • (七)Appdesigner-初步入门及常用组件的使用方法说明
  • (七)MySQL是如何将LRU链表的使用性能优化到极致的?
  • (十) 初识 Docker file
  • (一)pytest自动化测试框架之生成测试报告(mac系统)
  • (转)EOS中账户、钱包和密钥的关系
  • ./indexer: error while loading shared libraries: libmysqlclient.so.18: cannot open shared object fil
  • .NET C# 使用 iText 生成PDF
  • .net core 使用js,.net core 使用javascript,在.net core项目中怎么使用javascript
  • .NET DataGridView数据绑定说明
  • .NET/C# 项目如何优雅地设置条件编译符号?