@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{@Overridepublic void verifyOrderParameters() {System.out.println("校验订单参数");// 调用保存订单方法saveOrder();}@Override@Transactionalpublic void saveOrder() {System.out.println("保存订单信息到DB");}
}
我们用伪代码来演示一下Spring动态代理生成的代理类。
OrderServiceImplProxy
/*** 订单业务层具体处理类的代理类*/
public class OrderServiceImplProxy implements OrderService{/*** 持有被代理的具体的目标对象*/private OrderServiceImpl orderServiceImpl;public OrderServiceImplProxy(OrderServiceImpl orderServiceImpl) {this.orderServiceImpl = orderServiceImpl;}@Overridepublic void verifyOrderParameters() {orderServiceImpl.verifyOrderParameters();}@Overridepublic 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();
}@Transactionalpublic void insertOrder() {//SQL操作}
}
变更为:
@Service
public class OrderService {public void insert() {OrderService proxy = (OrderService) AopContext.currentProxy();proxy.insertOrder();}@Transactionalpublic void insertOrder() {//SQL操作}
}
@Transactional类内部访问失效原因详解相关推荐
- C++中空类占一字节原因详解
C++中空类占一字节原因详解 - XSH的博客 - CSDN博客 https://blog.csdn.net/xiong452980729/article/details/71077144 在C++中 ...
- C++友元函数和友元类(C++ friend)详解
在看VISP视觉库的时候遇到友元函数: Friends void swap (vpDetectorAprilTag &o1, vpDetectorAprilTag &o2) 在定义一个 ...
- Java类的加载过程详解 面试高频!!!值得收藏!!!
受多种情况的影响,又开始看JVM 方面的知识. 1.Java 实在过于内卷,没法不往深了学. 2.面试题问的多,被迫学习. 3.纯粹的好奇. 很喜欢一句话: 八小时内谋生活,八小时外谋发展. 望别日与 ...
- 中yeti不能加载_第二十章_类的加载过程详解
类的加载过程详解 概述 在 Java 中数据类型分为基本数据类型和引用数据类型.基本数据类型由虚拟机预先定义,引用数据类型则需要进行类的加载 按照 Java 虚拟机规范,从 Class 文件到加载到内 ...
- java类修饰词和内部类详解
java类修饰词和内部类详解 控制属性: 同一类内 同一包内 子类 所有类 public 可 可 可 ...
- Android 进阶——Framework 核心之Android Storage Access Framework(SAF)存储访问框架机制详解(一)
文章大纲 引言 一.Android Storage Access Framework 二.Storage Access Framework 的主要角色成员 1.Document Provider 文件 ...
- Android 进阶——Framework 核心之Android Storage Access Framework(SAF)存储访问框架机制详解(二)
文章大纲 引言 一.DirectFragment 1.当选中DirectoryFragment中RecyclerView的Item时 2.选中DirectoryFragment中RecyclerVie ...
- java访问修饰符详解——学java,零基础不怕,不只要理论,更要实践+项目,a href=http://www.bjweixin.com太原维信科技提供 /a...
java访问修饰符详解--学java,零基础不怕,不只要理论,更要实践+项目 <a href=http://www.bjweixin.com>太原维信科技提供 </a> pub ...
- colsure php_PHP_PHP中Closure类的使用方法及详解,Closure,匿名函数,又称为Anonym - phpStudy...
PHP中Closure类的使用方法及详解 Closure,匿名函数,又称为Anonymous functions,是php5.3的时候引入的.匿名函数就是没有定义名字的函数.这点牢牢记住就能理解匿名函 ...
最新文章
- EBGAN, LSGAN, BEGAN
- ubunto安装mysql8.13_ubuntu安装mysql[ubuntu部署]
- 企业网络推广“卡壳”了?如何更有效提升SEO排名?
- (三)html5的结构
- CVTE2016校招试题摘选
- [Java基础]哈希值
- [蓝桥杯][算法提高VIP]分分钟的碎碎念-dfs
- 李开复:21世纪7种人才最抢手
- [Diary]6.10
- 研讨会 | 知识图谱大咖云集阿里,他们都说了啥
- map的四种遍历方式
- 日本研发投篮机器人Cue,投球命中率接近100%
- 《Java程序员职场全攻略:从小工到专家》连载十:这条路大家都是怎么走的
- autosar架构详细介绍_干货|非常详细的 Ceph 介绍、原理、架构
- CAS132172-61-3阳离子脂质体DOTAP科研用
- 菜鸟、小白在autojs和冰狐智能辅助之间如何选择?
- Unsafe code may only appear if compiling with /unsafe
- GIS 通过osm2po离线最短路径和路径规划后台计算
- microsoft excel使用技巧和问题解决
- 数据库—属性 码 候选码 主码 外码 主属性 非主属性
热门文章
- (学习日记)2023.04.25
- 为何汽车制造商需要关注HTML5
- 关闭远程,模拟鼠标键盘失效!
- 先装Vista后装XP双系统的方法
- javaweb基于JSP+Servlet开发北京市地铁(火车票)订票系统+论文+PPT+任务书+检查表 毕业设计
- html中的样式写在什么位置,css样式放在哪里?
- php高强度精密涂覆钢管,双面涂塑钢管需求和发展 矿用涂塑复合钢管使用常识...
- 去耦、旁路、滤波电容的区别
- 用十年教会自己编程_什么学习编程实际上教会了我
- 微信红包程序c语言,C语言实战番外篇——模拟微信抢红包