这是一个非常常见的关于 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事务的传播机制的更多相关文章

  1. 数据库的特性与隔离级别和spring事务的传播机制和隔离级别

    首先数据库的特性就是 ACID: Atomicity 原子性:所有事务是一个整体,要么全部成功,要么失败 Consistency 一致性:在事务开始和结束前,要保持一致性状态 Isolation 隔离 ...

  2. Spring事务之传播机制

    Spring事务传播机制:Spring在TransactionDefinition接口中规定了种类型的事务传播行为,它们规定了事务方法和事务方法发生嵌套时事务如何进行传播.即协调已经有事务标识的方法之 ...

  3. spring事务的传播机制新解

    以下是事物的传播机制: @Transactional(propagation=Propagation.REQUIRED)如果有事务, 那么加入事务, 没有的话新建一个(默认情况下)@Transacti ...

  4. 通俗易懂的spring事务的传播机制讲解!

    spring事务理解 前提两个都是事务的方法,并且两个方法会进行调用,调用方统一使用required 举例有两个方法: required 如果当前上下文存在事务,被调用方则加入该调用方的事务,没有的话 ...

  5. Spring事务的传播行为 @Transactional(转)

    Spring事务的传播行为 在service类前加上@Transactional,声明这个service所有方法需要事务管理.每一个业务方法开始时都会打开一个事务. Spring默认情况下会对运行期例 ...

  6. Spring事务的传播行为 @Transactional

    Spring事务的传播行为http://blog.csdn.net/cuker919/article/details/5957209 在service类前加上@Transactional,声明这个se ...

  7. 关于事务,事务的特性,spring事务的传播特性

    1.什么是事务: 事务是程序中一系列严密的操作,所有操作执行必须成功完成,否则在每个操作所做的更改将会被撤销,这也是事务的原子性(要么成功,要么失败). 2.事务特性: 事务特性分为四个:原子性(At ...

  8. Spring事务的传播特性和隔离级别

    事务的几种传播特性1. PROPAGATION_REQUIRED: 如果存在一个事务,则支持当前事务.如果没有事务则开启2. PROPAGATION_SUPPORTS: 如果存在一个事务,支持当前事务 ...

  9. Spring事务的传播行为

      本文主要介绍下Spring事务中的传播行为. 事务传播行为介绍 Spring中的7个事务传播行为: |事务行为|说明 | |:--|:--| |PROPAGATION_REQUIRED | 支持当 ...

  10. Spring事务的传播:PROPAGATION_REQUIRED

    PROPAGATION_REQUIRED-- 支持当前事务,如果当前没有事务,就新建一个事务.这是最常见的选择. ServiceA { void methodA() { ServiceB.method ...

随机推荐

  1. Go语言遍历字符串——获取每一个字符串元素

    遍历字符串有下面两种写法. 遍历每一个ASCII字符 遍历 ASCII 字符使用 for 的数值循环进行遍历,直接取每个字符串的下标获取 ASCII 字符,如下面的例子所示. theme := &qu ...

  2. Centos 安装 nload (流量监控)

    QQ交流群:646559931.系统安装基本工具[root@localhost ~]# yum install -y gcc gcc-c++ make flex byacc libpcap ncurs ...

  3. Top 出海 AI 公司招技术!HIX.AI & Pollo.ai | 深圳

    HIX.AI & Pollo.ai 招聘高级海外 AI 产品经理 (25-45K) 岗位职责: 负责Web 端海外 AI 产品的规划与策划,负责产品需求分析及原型设计,并制定方案推动产品研发落 ...

  4. delphi获得唯一ID字符串

    //这是我三层开发中常用的一个函数,直接调用CreateSortID uses System.Win.ComObj,System.RegularExpressions,System.StrUtils, ...

  5. ANSYS实体单元施加扭矩方法分析

    ANSYS 结构分析单元与应用-王新敏等(P199) 此处以等截面椭圆柱为例. 对实体单元施加扭矩,主要方法如下: 引入质量单元 MASS21 并新建顶面的中心节点,随后将顶面所有节点通过 cerig ...

  6. BaseMultiTableInnerInterceptor源码解读

    本文首发在我的博客:https://blog.liuzijian.com/post/mybatis-plus-source-multi-table-inner-interceptor.html 一.概 ...

  7. Docker部署RocketMQ(JDK11)

    说起微服务,不谈容器,不谈云,那还谈个啥?容器中又以Docker最为流行,那么我们今天就来实践下容器化微服务,然后顺带解决下各种疑难杂症. 环境: Idea2019.03/Gradle6.0.1/JD ...

  8. while(bug)

    while(bug) { // 加了班也不一定写的完代码 // 写完了代码也不一定编译的过 // 编译过了也不一定没bug // 有了bug也不一定找的到 // 找到bug也不一定改的了 // 改了这 ...

  9. 如何开发 MCP 服务?保姆级教程!

    最近这段时间有个 AI 相关的概念特别火,叫 MCP,全称模型上下文协议(Model Context Protocol).这是由 Anthropic 推出的一项开放标准,目标是为大型语言模型和 AI ...

  10. Vue的前端项目开发环境搭建

    一.本机window端:安装Node.js,其实质性功能相当于,java的maven https://nodejs.org/en/download/ 二.本机window端:检查Node.js的版本 ...