Spring AOP与Spring 事务

news2024/12/24 11:26:10

一、AOP讲解

  1. 创建普通对象UserService
@Component
public class UserService{
	@Autowired
	private OrderService orderService;
	public void test(){
		System.out.println(orderService);
	}

}
  1. 创建代理对象UserServiceProxy,对test()方法进行切面编程
@Aspect
@Component
public class ZhouyuAspect{
	@Before("execution(public void com.zhouyu.service.UserService.test())")
	public void zhouyuBefore(JoinPoint joinPoint){
		System.out.println("zhouyuBefore");
	}
}
  1. 上述代码的伪代码相当于
class UserServiceProxy extends UserService{
	执行切面逻辑代码;
	super.test();	//执行父类方法
}
  1. 此时装入单例池Map中的Bean对象就是代理对象UserServiceProxy,所以我们拿出来的bean对象是UserServiceProxy代理对象
  • 现在来思考一个问题,在普通对象userService的属性orderService,有@Autowired进行依赖注入,那么orderService是有值的。但是在初始化后,进行了AOP生成了代理对象userServiceProxy,userServiceProxy的属性orderService并没有注入依赖,是null,这就来问题了。
  • 其实第3点的伪代码应该改成如下,这样就解决了null值得问题了,下面说说为什么。
  • 试想一下,生成普通对象userService,并为普通对象userService的属性orderService依赖注入,那么为什么生成代理对象userServiceProxy,不为代理对象userServiceProxy的属性orderService进行依赖注入呢?Spring认为是没必要的,就像下面的伪代码一样,除了执行AOP切面编程的代码之外,还是用回普通对象userService属性和方法
  • 所以一句话说完:UserServiceProxy代理对象做Bean对象,除了切面编程@Before会执行代理对象,其他的方法和属性可以认为是在执行普通对象
class UserServiceProxy extends UserService{
	UserService target;

	执行切面逻辑
	target.test();	//执行父类方法
}

在这里插入图片描述

二、Spring事务

Spring事务是基于AOP实现的,下面以SQL语句为例子。
1. 使用@Transactional为test方法做AOP

@Transactional				//回滚——Spring事务
public void test(){
	jdbcTemplate.execute("insert into t1 values(1,1,1,1,'1')");
	throw new NullPointerException();
}
  • @Transactional对应的伪代码
public class UserServiceProxy extends UserService{
	UserService target;
	
	//不难看出来1.2.3.4.6都是对test做一个切面,由UserServiceProxy代理对象执行;
	//test方法由普通对象执行
	public void test(){
		1. 事务逻辑
		2. 开启事务
		3. 事务管理器去创建数据库连接conn并放入了ThreadLocal
		4. conn.autocommit = false
		5. target.test();		//UserService普通对象.test() jdbcTemplate conn sql语句
		6. SQL没问题就conn.commit(),否则就conn.rollback();
	}
}
  • autocommit = true对应的功能
  • 如果数据库由jdbcTemplate连接,autocommit默认为true,则执行完SQL语句之后就会自动提交
  • 如果数据库由Spring连接,那么Spring就会把autocommit改成false,则执行完SQL语句之后还不会自动提交
  • 所以数据库创建必须由Spring来进行,但是如果由Spring创建数据库,那么Spring一启动就要连接数据库,万一我们不用数据库呢?不用就不用呗,哈哈哈哈!

2. 总结Spring事务

  • 普通对象执行的是UserService.test();
  • 代理对象执行的是UserServiceProxy.test()= @Transactional + UserService.test();

3. 特殊场景

@Transactional
public void test(){
	jdbcTemplate.execute("insert into t1 values (1,1,1,1,'1')");
	a();
}

//功能:出现事务就出现异常报告
@Transactional(propagation = Propagation.NEVER)		
public void a(){
	jdbcTemplate.execute("insert into t1 values(2,2,2,2,'2')");
}

//测试方法
userServiceProxy.test();
测试结果:Process finished with exit code 0(没有任何信息)

我们根据上面两点来分析这个结果

  • 代理对象userServiceProxy先执行了事务@Transactional,然后再由普通对象执行test方法体,当执行到a方法的时候,仍然由普通对象执行,那么这时候a方法的@Transactional(propagation = Propagation.NEVER) 事务就不会被识别到。所以测试结果没有报错:Process finished with exit code 0(没有任何信息)

那么如何让a方法执行@Transactional(propagation = Propagation.NEVER)这个事务

public class OrderService{
	@Transaction(propagation = Propagation.NEVER)
	public void a(){
		jdbcTemplate.execute("insert into t1 values(2,2,2,2,'2')");
	}
}

public class UserService{
//1. 因为这里注入的Bean是代理对象
	@Autowired
	private OrderService orderService;

	@Transaction
	public void test(){
		jdbcTemplate.execute("insert into t1 values(1,1,1,1,'1')");
//2. 由代理对象执行a方法
		orderService.a();
	}
}

测试:Existing transaction found for transaction marked with propagation…

  • 分析:因为这一次的a()方法是代理对象UserServiceProxy的orderService属性的方法,所以a()方法的执行是在代理对象UserServiceProxy下执行的,可以执行事务,即可以存在事务,所以@Transactional(propagation = Propagation.NEVER)会被识别到。

4. 多线程属于同一个事务吗?

public class OrderService{
	@Transactional
	public void test(){
		jdbcTemplate.execute("insert into t1 values(1,1,1,1,'1')");
	}
}

public class UserService{
	@Autowired
	OrderService orderService;
	
	//1. 事务管理器去创建数据库连接conn并放入了ThreadLocal,执行的时候再拿出来
	orderService.test();

	//2. 这里执行test会去ThreadLocal寻找数据库二连接conn,但是发现找不到,就会自己创建数据库连接
	new Thread(new Runnable(){
		@Override
		public void run(){
			orderService.test();
		}
	}).start();

	//1和2都通过不同数据库链接来连接数据库,所以肯定不在同一个事务中
}

5. 方法修饰词private和事务

public class UserService{
	@Transaction
	private void test(){
		System.out.println("测试数据库回滚事务");
	}
}

执行结果:报错

分析:

  1. 事务的实质是AOP,AOP的实质是继承,所以事务的实质是继承
  2. 父类private修饰的方法,子类无法访问重写
  3. 所以父类private修饰的方法,无法进行AOP,也无法进行事务
  4. 那么@Transaction就会报错

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/175354.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SSM项目 - 博客系统

1.SSM 版本的博客系统相较于 Servlet 版本的升级1. 框架升级 : SSM (SpringBoot Spring MVC MyBatis) MySQL Redis jQuery.2. 密码升级: 明文存储/md5存储 -> 加盐处理.3. 用户登录状态持久化升级: session 持久化到内存 - > session 持久化到 Redis. (后期有空实现…

cmake 03 一个可用的 cmake 工程应当是什么样的

cmake 学习笔记 代码地址: https://gitcode.net/u014254963/cmake-study/-/tree/master/hello_cmake_project https://gitcode.net/u014254963/cmake-study/-/tree/master/hello_cmake_project_vs 本文目标 多目录构建引用自己写的动态库关于单元测试的一些实践使用 python 脚…

Pandas-DataFrame基础知识点总结

1、DataFrame的创建 DataFrame是一种表格型数据结构,它含有一组有序的列,每列可以是不同的值。DataFrame既有行索引,也有列索引,它可以看作是由Series组成的字典,不过这些Series公用一个索引。 DataFrame的创建有多种…

JavaEE-多线程初阶4

✏️作者:银河罐头 📋系列专栏:JavaEE 🌲“种一棵树最好的时间是十年前,其次是现在” 目录多线程案例阻塞队列阻塞队列是什么生产者消费者模型标准库中的阻塞队列阻塞队列实现定时器定时器是什么标准库中的定时器实现定…

(第107篇)C规范编辑笔记(十三)

往期文章: C规范编辑笔记(一) C规范编辑笔记(二) C规范编辑笔记(三) C规范编辑笔记(四) C规范编辑笔记(五) C规范编辑笔记(六) C规范编辑笔记(七) C规范编辑笔记(八) C规范编辑笔记(九) C规则编辑笔记(十) C规范编辑笔记(十一) C规范编辑笔记(十二) 正文&#xff…

行人属性识别研究综述(二)

文章目录6 PAR(行人属性识别)算法综述6.1全局基于图像的模型6.1.1 ACN (iccvw-2015)6.1.2 DeepSAR and DeepMAR (ACPR-2015) [6]6.1.3 MTCNN (TMM-2015) [7]6.2 基于部件的模型6.2.1 Poselets (ICCV-2011)6.2.2 rad (iccv-2013)6.2.3 PANDA (cvp -2014) …

Java-IO知识详解(一)

分类分类(传输,操作)IO理解分类 - 从传输方式上字节流字符流字节流和字符流的区别IO理解分类 - 从数据操作上文件(file)数组([])管道操作基本数据类型缓冲操作打印对象序列化反序列化转换装饰者模式分类(传输,操作&…

迈百瑞冲刺创业板上市:关联收入占比较高,房健民为加拿大籍

撰稿|汤汤 来源|贝多财经 近日,烟台迈百瑞国际生物医药股份有限公司(下称”迈百瑞“)在深圳证券交易所提交更新后的招股书(申报稿)。据贝多财经了解,迈百瑞于2022年9月在递交IPO申请材料,准备…

指定不同版本的pcl

18.04里面安装了两个版本的pcl,一个是安装ros的时候安装的pcl1.8,另一个是安装的源码pcl1.12版本。一直相安无事,今天在我编译lego-loam的时候,突然就冲突了。卡了我两个小时,到处找原因,网上基本上没有相似…

RSD高分卫星数据处理能力提升——日正射处理数千景高分数据集

李国春 通常认为,能够单日处理几百景高分辨率对地观测卫星数据的系统就已经是非常优秀的卫星数据处理系统了。RSD此次优化将其处理能力提升超过了一个数量级,达到了单日正射处理数千景高分辨率卫星数据集的水平。 不仅如此,RSD达到如此高的…

SpringBoot+Vue项目(学生信息管理系统)搭建运行

项目地址:学生信息管理系统 前端部分(Vue) 首先以管理员身份运行终端 不然运行命令时有些会报错 1.首先下载node.js 2.打开并安装node.js 3.安装完成,打开控制台,输入node -v查看是否安装完成,如果显示…

MongoDB学习笔记【part2】数据库、文档、集合与常用命令

一、MongoDB 概念 Mongo 与 SQL 的术语区别如下: SQL术语/概念MongoDB术语/概念解释/说明databasedatabase数据库tablecollection数据表 – 集合rowdocument记录 – 文档columnfield字段 – 域indexindex索引table joins表连接,MongoDB不支持primary k…

分享121个PHP源码,总有一款适合您

PHP源码 分享121个PHP源码,总有一款适合您 下面是文件的名字,我放了一些图片,文章里不是所有的图主要是放不下..., 121个PHP源码下载链接:https://pan.baidu.com/s/1--fhiwI0gwB1a2ouivPw7g?pwdd61x 提取码&#x…

监控指标解读和JVM 分析调优

1、中间件指标  当前正在运行的线程数不能超过设定的最大值。一般情况下系统性能较好的情况下,线 程数最小值设置 50 和最大值设置 200 比较合适。  当前运行的 JDBC 连接数不能超过设定的最大值。一般情况下系统性能较好的情况下, JDBC 最小值设置 …

Transformers学习笔记4

Tokenizernlp任务的输入都是raw text,model的输入需要是inputs id,所以tokenzier将句子转换成inputs id,怎么转换呢,有3种方式:word-basedsplit the text:按照空格来区分按照标点来区分我们会得到一个非常大…

Element-UI的dialog对话组件内的tinymce弹窗被遮挡的解决办法及其它相关注意事项

问题一&#xff1a;tinymce的弹窗被遮挡 问题截图 解决办法 修改层级 注意要写在 <style></style> 中&#xff0c;我当时没注意&#xff0c;写在了 <style scoped></style> 中&#xff0c;死活没反应。 <style> /* 在el-dialog中tinymce z-ind…

C进阶_指针和数组试题解析

农历新年即将到来&#xff0c;我在这里给大家拜年了&#xff01;祝大家新的一年心想事成&#xff0c;皆得所愿。新的一年&#xff0c;新的征程&#xff0c;愿各位继续怀揣梦想和远方&#xff0c;奔赴每一场山海。我们一起砥砺前行&#xff0c;“卯定乾坤”&#xff01; 老老少…

Spring Boot操作数据库学习之整合JDBC

文章目录一 Spring Data简介二 Spring Boot集成JDBC2.1 项目创建步骤2.2 测试的SQL脚本2.3 编写yaml配置文件连接数据库2.4 IDEA连接数据库步骤【非必要的步骤】2.5 测试2.6 运行结果2.7 对运行结果的探究2.8 遇到的错误2.8.1 问题1&#xff1a;jdk编译版本2.8.2 解决方法2.8.3…

低成本搭建一台 Unraid 家庭存储服务器:中篇

虎年最后一篇文章&#xff0c;接着上一篇内容&#xff0c;聊聊如何提升硬件的易用性问题。 写在前面 如果你的诉求非常简单、明确&#xff0c;不需要界面&#xff0c;上一篇内容中的 Ubuntu Server 应该已经能够完成你的诉求了。 但是&#xff0c;如果你和我一样&#xff0c…

【Java数据结构与算法】day4-稀疏数组和队列(环形队列)

✅作者简介&#xff1a;热爱Java后端开发的一名学习者&#xff0c;大家可以跟我一起讨论各种问题喔。 &#x1f34e;个人主页&#xff1a;Hhzzy99 &#x1f34a;个人信条&#xff1a;坚持就是胜利&#xff01; &#x1f49e;当前专栏&#xff1a;Java数据结构与算法 &#x1f9…