Spring 面试题——事务

目录

  • 1.谈谈对 Spring 事务的理解。
  • 2.Spring 管理事务的方式有哪几种?
  • 3.✨Spring 事务底层源码是如何实现的?
    • 3.1.后置处理
    • 3.2.事务执行
    • 3.3.总结
  • 4.@Transactional 注解有什么作用?它的常用属性有哪些?
  • 5.✨Spring 事务中的传播行为是指什么?具体有哪几种传播行为?
  • 6.Spring 中如何设置传播行为?

1.谈谈对 Spring 事务的理解。

(1)概念:Spring 事务是 Spring 框架提供的一种用于处理数据库事务的机制。在传统的 JDBC 中,我们需要手动管理事务的开启、提交和回滚,这样的代码实现非常繁琐且容易出错,而 Spring 事务通过对事务进行封装,提供了一种更方便、更简单的方式来管理事务。

(2)底层实现原理:Spring 的事务管理是通过 Spring AOP 功能实现的,它在方法调用前后进行事务的管理和控制。以声明式事务管理为例,通过在方法或类上添加 @Transactional 注解,Spring 会在执行方法时自动为其创建事务,并在方法执行完成后根据执行结果决定是否提交或回滚事务。通过使用 Spring AOP 和事务管理,可以实现业务逻辑和横切关注点的松耦合,并实现更可维护和可扩展的代码。

(3)特性:Spring 事务的关键特性以下几点:

  • 多种管理事务的方式:Spring 提供了多种管理事务的方式,例如声明式事务编程式事务,我们根据实际情况选取对应的方式。
  • 多种传播行为:Spring 事务提供了 7 种传播行为,如 REQUIRED(如果没有事务,则创建一个新事务;如果有事务,则加入当前事务)、REQUIRES_NEW(无论是否存在事务,都创建一个新事务)、NESTED(嵌套事务,创建一个保存点,允许内部事务独立提交或回滚)等。这些传播行为可以根据业务需求进行配置,实现对事务的精确控制
  • 隔离级别:Spring 事务支持多种隔离级别,如 READ_UNCOMMITTED(读未提交)、READ_COMMITTED(读已提交)、REPEATABLE_READ(可重复读)、SERIALIZABLE(串行化)等。通过配置隔离级别,我们可以控制事务对于其他事务的可见性和并发行为,确保数据的隔离性。
  • 异常处理:Spring 事务提供了异常处理机制,可以配置需要回滚的异常类型和不需要回滚的异常类型。当方法中抛出指定类型的异常时,事务将回滚或不回滚,从而可以对事务执行过程中发生的异常进行精细的管理

2.Spring 管理事务的方式有哪几种?

Spring 管理事务的方式有以下三种:

  • 编程式事务管理:编程式事务管理是通过在代码中编写事务管理相关的代码实现的。这种方式需要手动控制事务的开启、提交和回滚,代码比较繁琐。在 Spring 中,可以使用 TransactionTemplate 或者直接使用 PlatformTransactionManager 接口的实现类来实现编程式事务管理。
  • 声明式事务管理:声明式事务管理是通过在配置文件或者注解@Transactional 中声明事务的相关信息来实现的。这种方式可以将事务的控制从代码中分离出来,使得代码更加简洁。在 Spring 中,可以使用 AOP 技术来实现声明式事务管理,通过在配置文件中配置切面和通知,使得 Spring 在执行方法时自动应用事务管理。

3.✨Spring 事务底层源码是如何实现的?

Spring 事务的源码部分大体上可以分为 2 步:创建目标 Bean 的后置处理和事务执行。

3.1.后置处理

(1)第一步就是后置处理,在创建目标 Bean 的后置处理器中,主要是做下面两件事情。

(2)首先会获取到所有的切面信息,然后和目标 Bean 的所有方法进行匹配,然后找到目标 Bean 所有需要进行事务处理的方法,匹配成功的方法。此外,还需要将事务属性保存到缓存 attributeCache 中。attributeCache 是一个 Map 结构,其中的 key 保存的是方法对象,value 保存的是该方法对应的属性信息。

public abstract class AbstractFallbackTransactionAttributeSource implements TransactionAttributeSource {//...	final Map<Object, TransactionAttribute> attributeCache = new ConcurrentHashMap<>();
}

(3)然后就是创建 AOP 代理对象。在该过程中涉及到一个名为 AbstractAutoProxyCreator 的类,该类实现了 BeanPostProcessor 接口,并且重写了后置处理方法 postProcessAfterInitialization,该方法在 Bean 的初始化之后被调用,它允许开发者在初始化之前对 Bean 进行一些自定义的操作。postProcessAfterInitialization 方法中调用了 wrapIfNecessary 方法,该方法主要执行逻辑是:

  • 根据已知的相关信息调用 createProxy 方法来获取目标 Bean 代理对象,Spring 源码中的 AopProxy 接口定义了创建代理对象的方法,并且它有两个实现类,分别对应 2 种创建 AOP 代理对象的方式:
    • 如果是基于接口的代理,则选择使用 JDK 动态代理,对应 JdkDynamicAopProxy 类;
    • 如果是基于类的代理,则选择使用 CGLIB 动态代理,对应 CglibAopProxy 类;

3.2.事务执行

(1)回到业务逻辑,通过目标 Bean 的 AOP 代理对象,开始执行主方法。在执行事务时会调用 TransactionInterceptor 中的 invoke 方法,里面会调用事务执行的核心方法,即 TransactionAspectSupport 类中的 invokeWithinTransaction 方法,其源码如下:

public abstract class TransactionAspectSupport implements BeanFactoryAware, InitializingBean {//...protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,final InvocationCallback invocation) throws Throwable {//获取我们的事务属源对象TransactionAttributeSource tas = getTransactionAttributeSource();//通过事务属性源对象获取到我们的事务属性信息final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);//获取我们配置的事务管理器对象final PlatformTransactionManager tm = determineTransactionManager(txAttr);//从tx属性对象中获取出标注了@Transactionl的方法描述符final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);//处理声明式事务if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {//有没有必要创建事务TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);Object retVal;try {//调用钩子函数进行回调目标方法retVal = invocation.proceedWithInvocation();}catch (Throwable ex) {//抛出异常进行回滚处理completeTransactionAfterThrowing(txInfo, ex);throw ex;}finally {//清空我们的线程变量中transactionInfo的值cleanupTransactionInfo(txInfo);}//提交事务commitTransactionAfterReturning(txInfo);return retVal;}//编程式事务else {//这里不是我们的重点,省略...}}
}

(2)invokeWithinTransaction 方法的主要执行逻辑如下:

  • 获取事务属性:从 attributeCache 缓存中获取事务的缓存数据,即 TransactionAttribute 对象;
  • 创建事务:通过 createTransactionIfNecessary 方法创建并开启事务;
  • 执行逻辑:调用 proceedWithInvocation 方法,开始执行业务逻辑。在执行过程中可能出现以下两种情况:
    • 如果在执行过程中没有出现异常或者错误,则最后提交事务,整个流程结束;
    • 如果在执行过程中抛出异常,则会进入 completeTransactionAfterThrowing 方法,走后续的事务回滚操作。至于具体是否执行回滚操作,或者针对哪些指定的异常执行回滚操作,则与事务属性 rollbackFor 或者 noRollbackFor 的具体配置有关;

3.3.总结

总的来说,Spring 事务底层实现主要分为 2 步:

  • 先匹配出目标 Bean 对象所有关于事务的切面列表,并将匹配成功的事务属性保存到 advisorsCache 缓存中;
  • 从缓存取出事务属性,然后创建事务、启动事务,执行业务逻辑,最后提交或者回滚事务。

相关文章:
61 张图,剖析 Spring 事务,就是要钻到底!
Spring 面试题——AOP

4.@Transactional 注解有什么作用?它的常用属性有哪些?

(1)@Transactional 注解是一个用于声明事务的注解,用于在方法或类级别上标记为事务性。它的作用是告诉 Spring 框架要对带有该注解的方法或类进行事务处理

(2)@Transactional 注解有以下几个常用属性:

  • propagation:指的是一个事务方法被另一个事务方法调用时,事务如何传播,默认值为 REQUIRED
  • isolation:表示事务的隔离级别,默认值为 DEFAULT。隔离级别指的是多个事务同时访问数据库时的数据隔离程度,常用的隔离级别包括:
    • DEFAULT:使用数据库默认的隔离级别。
    • READ_UNCOMMITTED:允许读取未提交的数据变更。
    • READ_COMMITTED:只能读取已经提交的数据变更。
    • REPEATABLE_READ:可重复读,确保多次读取的结果一致。
    • SERIALIZABLE:串行化,最高的隔离级别,确保事务串行执行。
  • readOnly:表示事务是否为只读事务,默认值为 false。如果将其设置为 true,表示该事务只读取数据而不更新数据,可以用于优化事务性能。
  • timeout:表示事务的超时时间,默认值为 -1,表示不超时。超时时间是指事务执行的最长时间,超过该时间,则事务会被自动回滚。
  • rollbackFor:指定异常类型数组,当方法抛出指定类型的异常时,事务会回滚。示例:@Transactional(rollbackFor = {Exception.class})
  • rollbackForClassName:指定异常类型名称数组,当方法抛出指定类型的异常时,事务会回滚。示例:@Transactional(rollbackForClassName = {“Exception”})
  • noRollbackFor:指定异常类型数组,当方法抛出指定类型的异常时,事务不会回滚。示例:@Transactional(noRollbackFor = {CustomException.class})
  • noRollbackForClassName:指定异常类型名称数组,当方法抛出指定类型的异常时,事务不会回滚。示例:@Transactional(noRollbackForClassName = {“CustomException”})

(3)注意:回滚属性可以单独使用,也可以组合使用,以定义回滚策略。如果不指定回滚属性,默认情况下,事务会在遇到 RuntimeException 及其子类抛出时回滚

相关知识点:
MySQL 面试题——事务

(3)Transactional 注解的源码如下所示:

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Transactional {@AliasFor("transactionManager")String value() default "";@AliasFor("value")String transactionManager() default "";Propagation propagation() default Propagation.REQUIRED;Isolation isolation() default Isolation.DEFAULT;int timeout() default TransactionDefinition.TIMEOUT_DEFAULT;boolean readOnly() default false;Class<? extends Throwable>[] rollbackFor() default {};String[] rollbackForClassName() default {};Class<? extends Throwable>[] noRollbackFor() default {};String[] noRollbackForClassName() default {};}

相关文章:
拜托!面试请不要再问我 @Transactional
MySQL 面试题——事务

5.✨Spring 事务中的传播行为是指什么?具体有哪几种传播行为?

(1) 事务中的传播行为解决的核心问题是多个声明了事务的方法相互调用的时候存在的事务嵌套问题,那么这个事务的行为应该如何进行传递呢?比如说 methodA() 调用 methodB(),两个方法都显示地开启了事务,那么 methodB() 是开启一个新事务,还是继续在 methodA() 的事务中执行呢?这就取决于事务的传播行为

(2)所以 Spring 为了解决这个问题,定义了以下 7 种事务传播行为:

传播属性描述
REQUIRED如果有事务在运行,当前的方法就在这个事务内运行,否则,就启动一个新的事务,并在自己的事务内运行(默认的)
REQUIRED_NEW无论当前是否存在事务,都必须创建一个新事务。如果当前存在事务,将会被挂起,并在新事务结束后恢复。即使外部事务回滚,新事务也不受影响
NESTED如果有事务在运行,当前的方法就应该在这个事务的嵌套事务内运行.否则,就启动一个新的事务,并在它自己的事务内运行
MANDATORY强制事务执行,当前的方法必须运行在事务内部;如果没有正在运行的事务,就抛出异常
SUPPORTS支持事务,如果有事务在运行,当前的方法就在这个事务内运行;否则以非事务的方式执行
NOT_SUPPORTED不支持事务,以非事务的方式执行,如果有运行的事务,将它挂起
NEVER以非事务的方式执行,如果有运行的事务,就抛出异常

Spring 事务中的事务传播行为是指在一个方法内部调用另一个带有事务的方法时,事务如何传播到被调用的方法中的行为

6.Spring 中如何设置传播行为?

(1)在 Spring 中设置事务传播行为,可以通过在 @Transactional 注解中设置 propagation 属性来实现。propagation 属性的默认值是 REQUIRED,也就是使用当前事务,如果不存在则新建事务。

(2)例如,使用 REQUIRED 传播行为的示例:

@Service
@Transactional(propagation = Propagation.REQUIRED)
public class UserServiceImpl implements UserService {// ...
}

在这个示例中,@Transactional 注解的 propagation 属性被设置为 REQUIRED,也就是在该方法内使用当前事务,如果不存在则新建一个事务。可以根据需要将 propagation 属性设置为其他的传播行为,如 SUPPORTS、MANDATORY、REQUIRES_NEW、NOT_SUPPORTED、NEVER 或 NESTED。

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

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

相关文章

ansible常用模块介绍

ansible运行模块的两种方式 Ad - Hoc 利用 ansible 命令直接完成管理 &#xff0c; 主要用于临时命令使用场景 ansible westos -m shell -a ls /mnt playbook ansible 脚本 &#xff0c; 主要用于大型项目场景 &#xff0c; 需要前期的规划 vim test.yml - hosts: all task…

【栈】车队

题目&#xff1a; /** 单调栈&#xff1a;存储到终点的时间&#xff0c;需要考虑浮点数* 思路&#xff1a;首先按照距离进行排序&#xff08;目的&#xff1a;如果离终点远的车辆用时比前面的车辆用时短&#xff0c;则是一个车队)* 排序后计算每一辆车辆的时间如果用…

web:[SUCTF 2019]CheckIn(一句话木马,.user.ini)

题目 页面显示 上传文件&#xff0c;随便上传一个文件试试 上传了一个文本&#xff0c;显示失败&#xff0c;不是图片 那就换图片马上传试试 不能包含<?,换一种写法&#xff0c;需要加上GIF89a&#xff0c;进行exif_imagetype绕过 上传成功 这里用.user.ini或者用post传参…

甘草书店:#8 2023年11月22日 星期三「“说一套做一套”的甘草与麦田」

最近与甘草书店的投资方和意向投资方沟通&#xff0c;听取了来自不同领域不同人群的观点。他们讲的都有道理&#xff0c;但他们说的都不是甘草。就像“麦田”成立之前&#xff0c;世间没有“麦田”一样&#xff1b;“甘草”出现之前&#xff0c;世间没有也没有“甘草”。 故事…

力扣116. 填充每个节点的下一个右侧节点指针(详细讲解root根节点的理解)

题目&#xff1a; 给定一个 完美二叉树 &#xff0c;其所有叶子节点都在同一层&#xff0c;每个父节点都有两个子节点。二叉树定义如下&#xff1a; struct Node {int val;Node *left;Node *right;Node *next; } 填充它的每个 next 指针&#xff0c;让这个指针指向其下一个右…

220V工频正弦波逆变器设计

摘 要 与传统逆变器相比&#xff0c;工频正弦波逆变器具有电容电压应力低的优点。但是工频正弦波逆变器存在开关器件电压应力大和开关频率高的缺陷。将SPWM调制策略应用于工频正弦波逆变器&#xff0c;并在不产生电流纹波的条件下实现了最大调制度&#xff0c;不仅能够减小开关…

05.开闭原则(Open Closed Principle)

“你这个人怎么这么轴&#xff1f;让你改改以前的代码怎么和要了你命似的&#xff1f;难道你的能力仅限于此吗&#xff1f;” “你懂什么&#xff1f;我有我的原则&#xff01;我有我的信仰&#xff01;” 一言 开闭原则即&#xff1a;对扩展开放&#xff0c;对修改关闭&#…

D. In Love

贪心&#xff0c;维护最靠左的右端点以及最靠右的左端点 // Problem: D. In Love // Contest: Codeforces - Codeforces Round 905 (Div. 3) // URL: https://codeforces.com/contest/1883/problem/D // Memory Limit: 256 MB // Time Limit: 2000 ms // // Powered by CP Edi…

【从0配置JAVA项目相关环境1】jdk + VSCode运行java + mysql + Navicat + 数据库本地化 + 启动java项目

从0配置JAVA项目相关环境 写在最前面一、安装Java的jdk环境1. 下载jdk2. 配置jdk3. 配置环境变量 二、在vscode中配置java运行环境1. 下载VSCode2. 下载并运行「Java Extension Pack」 三、安装mysql1.官网下载MySQL2.开始安装如果没有跳过安装成功 3.配置MySQL Server4.环境变…

【爬虫】自动下载指定网站全部图片(Java版)

爬虫是一种自动化程序&#xff0c;能够模拟人类的浏览行为&#xff0c;访问网络资源并提取所需数据。它可以通过发送HTTP请求获取网页内容&#xff0c;并对网页进行解析和数据提取。 在大多数时候&#xff0c;提到爬虫我们就会想到 Python&#xff0c;其实 Java 也是可以实现爬…

判断完数(写出部分函数)

例如&#xff1a;本题要求实现一个函数&#xff0c;判断一个自然数是否是完数。如果一个自然数除自身之外的因子和等于它自己&#xff0c;则称该数为完数。例如 6 1 2 3&#xff1b;则6是完数。 函数接口定义&#xff1a; 在这里描述函数接口。&#xff1a;int isPerfect (…

ApplicationContextAware 类

优质博文&#xff1a;IT-BLOG-CN 需求&#xff1a; 使用autowired注入一些对象&#xff0c;但发现不可以直接使用Autowired&#xff0c;因为方法是static的&#xff0c;要使用该方法当前对象也必须是static&#xff0c;正常情况下Autowired无法注入静态的bean&#xff0c;于是…

数据结构与算法编程题44

有向无权图邻接矩阵表示 //参考博客&#xff1a;https://blog.csdn.net/qq_54162207/article/details/117414707#include <iostream> using namespace std;#define Maxsize 100 #define VertexmMaxNum 20 #define ERROR 0 #define OK 1 typedef string VertexType; …

img标签禁止右键点击复制图片等功能

场景描述&#xff1a;在网页中显示图片&#xff0c;但是不想让其他人右键保存图片 会用到一个新的属性&#xff1a;oncontextmenu 代码如下 <img src"./123.png" alt"" oncontextmenu"return false">这样虽然能解决不在当前页右键保存图片…

微信玩具小程序商城开发技巧

小程序已成为许多企业和个人开展业务的重要工具之一。如果你想在玩具行业中打造一个小程序商城&#xff0c;但又没有相关的编程经验&#xff0c;不用担心&#xff01;本文将通过乔拓云平台提供的简单操作步骤&#xff0c;分享给你玩具行业小程序平台搭建的教程。 首先&#xff…

DriveWorks——参数化设计非标定制利器

DriveWorks基本介绍 DriveWorks是一套被 SOLIDWORKS 认可为金牌合作伙伴产品的设计自动化软件。DriveWorks 可自动创建特定于订单的销售文档和 SOLIDWORKS 制造数据。减少重复性任务&#xff0c;消除错误&#xff0c;增加销售额&#xff0c;并在创纪录的时间内交付定制产品。 为…

Linux下的查看文件的命令

1. tail 命令 tail 命令是在 Linux 和类 Unix 系统上用来显示文件末尾内容的命令。它最常用于查看文件的末尾几行内容&#xff0c;通常在日志文件或其他不断更新的文件中使用。 以下是 tail 命令的常用选项和用法&#xff1a; 1.1. 基本用法 tail file_name这将默认显示文件…

python的异常处理批量执行网络设备的巡检命令

前言 在网络设备数量超过千台甚至上万台的大型企业网中&#xff0c;难免会遇到某些设备的管理IP地址不通&#xff0c;SSH连接失败的情况&#xff0c;设备数量越多&#xff0c;这种情况发生的概率越高。 这个时候如果你想用python批量配置所有的设备&#xff0c;就一定要注意这…

top K问题(C语言)

目录 前言 top K问题 模拟数据 建堆 验证&#xff08;简单了解即可&#xff09; 最终代码 调试部分 前言 在大小堆的实现&#xff08;C语言&#xff09;中我们讨论了堆的实际意义&#xff0c;在看了就会的堆排序&#xff08;C语言&#xff09;中我们完成了堆排序&#…

Java利用UDP实现简单的双人聊天

一、创建新项目 首先创建一个新的项目&#xff0c;并命名。 二、实现代码 import java.awt.*; import java.awt.event.*; import javax.swing.*; import java.net.*; import java.io.IOException; import java.lang.String; public class liaotian extends JFrame{ pri…