IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> @Transactional类内部访问失效原因详解 -> 正文阅读

[Java知识库]@Transactional类内部访问失效原因详解

一、原理

Spring之所以可以对开启@Transactional的方法进行事务管理,是因为Spring为当前类生成了一个代理类,然后在执行相关方法时,会判断这个方法有没有@Transactional注解,如果有的话,则会开启一个事务。

也就是说我们首先调用的是AOP代理对象而不是目标对象,首先执行事务切面,事务切面内部通过TransactionInterceptor环绕增强进行事务的增强,即进入目标方法之前开启事务,退出目标方法时提交/回滚事务。(该部分摘自:事务注解Transactional在同一个类中调用的失效问题_fastjson_的博客-CSDN博客

Spring在扫描bean的时候,如果扫描到方法上有这些注解,那么spring会通过动态代理模式,为这个bean动态地生成一个代理类,在代理类中,会对有注解的这个方法,做一些增强处理,如给有@Transactional注解的方法开启transaction。

当我们想要调用这个方法时,实际上是先调用了代理对象中被增强的方法,然后在代理对象中,又会调用我们实际的目标对象中的方法。在通过代理对象中转的这一过程中,像上边说的开启和提交transaction就实现了。(该部分摘自:@transactional注解_为啥同一个类中普通方法调用Spring注解方法,注解会失效?看完你就明白,So easy!..._weixin_39738667的博客-CSDN博客

二、代码模拟

实现机制我们大体知道了,下面我们用代码来模拟演示一下。

假设我们订单业务处理类中,有两个方法:校验订单参数方法verifyOrderParameters() 和 保存订单方法saveOrder(),其中saveOrder方法上加了@Transactional注解,verifyOrderParameters方法内会调用saveOrder方法。

OrderService

/**
 * 订单业务层的接口定义
 */
public interface OrderService {
 
    /**
     * 校验订单参数
     */
    void verifyOrderParameters();
 
    /**
     * 保存订单
     */
    void saveOrder();
}

OrderServiceImpl

/**
 * 订单业务层的具体处理类
 */
public class OrderServiceImpl implements OrderService{
 
    @Override
    public void verifyOrderParameters() {
        System.out.println("校验订单参数");
        // 调用保存订单方法
        saveOrder();
    }
 
    @Override
    @Transactional
    public void saveOrder() {
        System.out.println("保存订单信息到DB");
    }
}

我们用伪代码来演示一下Spring动态代理生成的代理类。

OrderServiceImplProxy

/**
 * 订单业务层具体处理类的代理类
 */
public class OrderServiceImplProxy implements OrderService{
 
    /**
     * 持有被代理的具体的目标对象
     */
    private OrderServiceImpl orderServiceImpl;
 
    public OrderServiceImplProxy(OrderServiceImpl orderServiceImpl) {
        this.orderServiceImpl = orderServiceImpl;
    }
 
    @Override
    public void verifyOrderParameters() {
        orderServiceImpl.verifyOrderParameters();
    }
 
    @Override
    public void saveOrder() {
        System.out.println("开启事务。。。");
        orderServiceImpl.saveOrder();
        System.out.println("提交事务。。。");
    }
}

这边我们来看下客户端调用saveOrder方法和verifyOrderParameters方法,输出结果都是什么样的。

public class Client {
 
    public static void main(String[] args) {
        // 创建一个订单业务的真实处理对象
        OrderServiceImpl orderServiceImpl = new OrderServiceImpl();
        // 创建一个代理对象
        OrderServiceImplProxy orderServiceImplProxy = new OrderServiceImplProxy(orderServiceImpl);
        // 执行代理对象的校验订单方法
        orderServiceImplProxy.verifyOrderParameters();
        System.out.println("--------------------------------------------");
        // 执行代理对象的保存订单方法
        orderServiceImplProxy.saveOrder();
    }
}

执行main方法后,得到下边的输出:

校验订单参数
保存订单信息到DB
--------------------------------------------
开启事务。。。
保存订单信息到DB
提交事务。。。

所以,普通方法verifyOrderParameters内调用注解方法saveOrder时,其实调用的是原目标对象(orderServiceImpl)的saveOrder方法,没有走代理对象(orderServiceImplProxy)中被增强的saveOrder方法,所以就不会产生效果啦。?

该部分摘自:@transactional注解_为啥同一个类中普通方法调用Spring注解方法,注解会失效?看完你就明白,So easy!..._weixin_39738667的博客-CSDN博客

三、解决方案

方法1:

将事务方法放到另一个类中进行调用。

方法2:

获取本对象的代理对象,再进行调用。具体操作如:

@Service
public class OrderService {
 
    private void insert() {
insertOrder();
}
 
@Transactional
    public void insertOrder() {
        //SQL操作
       }
}

变更为:

 @Service
public class OrderService {
 
  public void insert() {
 
    OrderService proxy = (OrderService) AopContext.currentProxy();
       proxy.insertOrder();
    }
 
    @Transactional
    public void insertOrder() {
        //SQL操作
       }
}

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-04-01 23:11:18  更:2022-04-01 23:13:41 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 7:32:01-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码