有关Spring事务的传播机制
这是一个非常常见的关于 Spring 事务传播机制 的问题,核心问题是:
在同一个类中,方法 A 调用方法 B,而方法 B 上有
@Transactional注解。当调用方法 A 时,如果发生异常,方法 B 的事务会生效吗?
简短回答:
不会生效!
在 Spring 中,默认使用的是基于 代理(Proxy) 的事务管理机制,只有外部调用带有@Transactional注解的方法时才会开启事务。
如果是同一个类中的方法直接调用(即内部调用),Spring 的事务注解将失效。
示例代码说明
@Service
public class MyService {
public void methodA() {
// 做一些操作
methodB(); // 内部调用methodB
}
@Transactional
public void methodB() {
// 数据库操作
}
}
️问题:
- 你调用
methodA(),它内部调用了methodB()。 - 即使
methodB()上有@Transactional注解,事务也不会生效!
为什么事务不生效?
因为 Spring 的事务是通过 动态代理(JDK Proxy 或 CGLIB) 实现的:
- 当你从外部调用
methodB(),Spring 会拦截这个调用,并在调用前后开启/提交事务。 - 但当你在类内部调用
methodB(),这是普通的 Java 方法调用,绕过了代理对象,Spring 无法进行事务控制。
如何解决这个问题?
方案一:将方法拆分到不同的类中
把 methodB() 放到另一个 Service 类中:
@Service
public class MyService {
@Autowired
private AnotherService anotherService;
public void methodA() {
// 做一些操作
anotherService.methodB(); // 外部调用
}
}
@Service
public class AnotherService {
@Transactional
public void methodB() {
// 数据库操作
}
}
这样事务就会生效了。
方案二:通过 AopContext.currentProxy() 获取代理对象(慎用)
你可以通过以下方式获取当前类的代理对象来调用 methodB():
@Service
public class MyService implements ApplicationContextAware {
private static ApplicationContext applicationContext;
@Transactional
public void methodB() {
// 数据库操作
}
public void methodA() {
// 获取当前类的代理对象
MyService proxy = (MyService) AopContext.currentProxy();
proxy.methodB(); // 使用代理调用
}
@Override
public void setApplicationContext(ApplicationContext ctx) {
applicationContext = ctx;
}
}
️ 注意事项:
- 需要在配置文件中启用暴露代理:
<aop:aspectj-autoproxy expose-proxy="true"/> - 或者使用注解方式:
@EnableAspectJAutoProxy(exposeProxy = true) - 此方式可实现功能,但会让代码耦合 Spring 框架,一般推荐优先使用方案一。
补充:事务传播行为(Propagation Behavior)
如果你希望方法B的行为能被方法A控制,可以指定事务传播行为,例如:
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void methodB() {
// 总是开启一个新事务
}
但这仍然需要保证 methodB() 是通过代理调用的才行。
总结
| 场景 | 事务是否生效 | 说明 |
|---|---|---|
同一类内调用带 @Transactional 的方法 |
不生效 | Spring 无法拦截内部方法调用 |
不同类之间调用带 @Transactional 的方法 |
生效 | 通过代理对象调用,事务生效 |
使用 AopContext.currentProxy() 调用 |
可以生效 | 需要设置 expose-proxy=true |
有关Spring事务的传播机制的更多相关文章
- 数据库的特性与隔离级别和spring事务的传播机制和隔离级别
首先数据库的特性就是 ACID: Atomicity 原子性:所有事务是一个整体,要么全部成功,要么失败 Consistency 一致性:在事务开始和结束前,要保持一致性状态 Isolation 隔离 ...
- Spring事务之传播机制
Spring事务传播机制:Spring在TransactionDefinition接口中规定了种类型的事务传播行为,它们规定了事务方法和事务方法发生嵌套时事务如何进行传播.即协调已经有事务标识的方法之 ...
- spring事务的传播机制新解
以下是事物的传播机制: @Transactional(propagation=Propagation.REQUIRED)如果有事务, 那么加入事务, 没有的话新建一个(默认情况下)@Transacti ...
- 通俗易懂的spring事务的传播机制讲解!
spring事务理解 前提两个都是事务的方法,并且两个方法会进行调用,调用方统一使用required 举例有两个方法: required 如果当前上下文存在事务,被调用方则加入该调用方的事务,没有的话 ...
- Spring事务的传播行为 @Transactional(转)
Spring事务的传播行为 在service类前加上@Transactional,声明这个service所有方法需要事务管理.每一个业务方法开始时都会打开一个事务. Spring默认情况下会对运行期例 ...
- Spring事务的传播行为 @Transactional
Spring事务的传播行为http://blog.csdn.net/cuker919/article/details/5957209 在service类前加上@Transactional,声明这个se ...
- 关于事务,事务的特性,spring事务的传播特性
1.什么是事务: 事务是程序中一系列严密的操作,所有操作执行必须成功完成,否则在每个操作所做的更改将会被撤销,这也是事务的原子性(要么成功,要么失败). 2.事务特性: 事务特性分为四个:原子性(At ...
- Spring事务的传播特性和隔离级别
事务的几种传播特性1. PROPAGATION_REQUIRED: 如果存在一个事务,则支持当前事务.如果没有事务则开启2. PROPAGATION_SUPPORTS: 如果存在一个事务,支持当前事务 ...
- Spring事务的传播行为
本文主要介绍下Spring事务中的传播行为. 事务传播行为介绍 Spring中的7个事务传播行为: |事务行为|说明 | |:--|:--| |PROPAGATION_REQUIRED | 支持当 ...
- Spring事务的传播:PROPAGATION_REQUIRED
PROPAGATION_REQUIRED-- 支持当前事务,如果当前没有事务,就新建一个事务.这是最常见的选择. ServiceA { void methodA() { ServiceB.method ...
随机推荐
- Go语言遍历字符串——获取每一个字符串元素
遍历字符串有下面两种写法. 遍历每一个ASCII字符 遍历 ASCII 字符使用 for 的数值循环进行遍历,直接取每个字符串的下标获取 ASCII 字符,如下面的例子所示. theme := &qu ...
- Centos 安装 nload (流量监控)
QQ交流群:646559931.系统安装基本工具[root@localhost ~]# yum install -y gcc gcc-c++ make flex byacc libpcap ncurs ...
- Top 出海 AI 公司招技术!HIX.AI & Pollo.ai | 深圳
HIX.AI & Pollo.ai 招聘高级海外 AI 产品经理 (25-45K) 岗位职责: 负责Web 端海外 AI 产品的规划与策划,负责产品需求分析及原型设计,并制定方案推动产品研发落 ...
- delphi获得唯一ID字符串
//这是我三层开发中常用的一个函数,直接调用CreateSortID uses System.Win.ComObj,System.RegularExpressions,System.StrUtils, ...
- ANSYS实体单元施加扭矩方法分析
ANSYS 结构分析单元与应用-王新敏等(P199) 此处以等截面椭圆柱为例. 对实体单元施加扭矩,主要方法如下: 引入质量单元 MASS21 并新建顶面的中心节点,随后将顶面所有节点通过 cerig ...
- BaseMultiTableInnerInterceptor源码解读
本文首发在我的博客:https://blog.liuzijian.com/post/mybatis-plus-source-multi-table-inner-interceptor.html 一.概 ...
- Docker部署RocketMQ(JDK11)
说起微服务,不谈容器,不谈云,那还谈个啥?容器中又以Docker最为流行,那么我们今天就来实践下容器化微服务,然后顺带解决下各种疑难杂症. 环境: Idea2019.03/Gradle6.0.1/JD ...
- while(bug)
while(bug) { // 加了班也不一定写的完代码 // 写完了代码也不一定编译的过 // 编译过了也不一定没bug // 有了bug也不一定找的到 // 找到bug也不一定改的了 // 改了这 ...
- 如何开发 MCP 服务?保姆级教程!
最近这段时间有个 AI 相关的概念特别火,叫 MCP,全称模型上下文协议(Model Context Protocol).这是由 Anthropic 推出的一项开放标准,目标是为大型语言模型和 AI ...
- Vue的前端项目开发环境搭建
一.本机window端:安装Node.js,其实质性功能相当于,java的maven https://nodejs.org/en/download/ 二.本机window端:检查Node.js的版本 ...