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

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 {
    @Autowired
    public void b() {
        this.c();
    }
    
    @Transactional
    public 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 {
    @Autowired
    private 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();
    }
​
    @Transactional
    public 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 {
    @Autowired
    private B b;
​
    @Transactional
    public 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 {
    @Autowired
    private C c;
​
    @Transactional
    public 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 {
​
    @Transactional
    public 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能捕获到并且进行添加事务。


http://www.kler.cn/a/287534.html

相关文章:

  • 抖音热门素材去哪找?优质抖音视频素材网站推荐!
  • 鸿蒙实现 web 传值
  • shell脚本_永久环境变量和字符串操作
  • 【3D Slicer】的小白入门使用指南九
  • Educational Codeforces Round 164 (Rated for Div. 2)(A~E)
  • IPv6 NDP 记录
  • SPI驱动学习三(spidev的使用)
  • 数据结构——顺序表和单链表
  • 论文精读-ReMoNet: Recurrent Multi-Output Network for Efficient Video Denoising
  • 如何轻松合并 PDF 文件
  • 27. 如何统计集合中每个元素的出现次数?请使用Map和Stream API举例说明。
  • Pinia 与 Vuex 对比
  • 【Nest 学习笔记】AOP切片编程
  • 页面滚动到指定位置——记录div滚动高度,并下次自动滚动到该位置
  • Java设计模式之单例模式详细讲解和案例示范
  • 华为云征文|Flexus X实例性能测评
  • 分贝通助力元气森林企业支出一体化降本提效
  • mysql 死锁 锁表的解决方法
  • Oracle高级sql语法学习之hits
  • vue按钮弹框
  • Leetcode Hot 100刷题记录 -Day3(双指针)
  • 【HTML】使用过程中的随记
  • C++入门8——vector的使用
  • 谷歌浏览器与edge哪个好用
  • 半导体芯闻--20240902
  • 百度广告联盟:抢占流量蓝海,精准营销新引擎