【面试】Spring事务面试考点吐血整理(建议珍藏)

Starting from a joke

问:把大象放冰箱里,分几步?

答:三步啊,第一、把冰箱门打开,第二、把大象放进去,第三、把冰箱门带上。

问:实现Spring事务,分几步?

答:三步啊,第一、找出需要事务的方法,第二、把事务加进去,第三、执行事务。

You may find it's not a joke, it's serious。

Try to find an entrance

当你面对一个完全不熟悉的事物时,一定要想办法找到一个突破口,然后逐步深入。那Spring事物的突破口在哪里呢?很明显在@EnableTransactionManagement注解里,因为是它启用了事物功能。

请看下图:

发现注解还引入了一个类TransactionManagementConfigurationSelector。

再来看这个类,如下图:

发现如果采用代理的方式时,又引入了一个类ProxyTransactionManagementConfiguration。

接着看这个类(重点来了),如下图:

发现这个类往容器中注册了3个bean,第一个是BeanFactoryTransactionAttributeSourceAdvisor。它以Advisor结尾说明它是Spring AOP范畴里的东西。

在AOP里,Advisor = Pointcut + Advice,Pointcut是切入点,表示要拦截的方法,Advice是增强,表示要加进去的事物功能。

再看看另外两个注册的bean,就是和这两个相关的。其中TransactionInterceptor就是一个Advice,因为它实现了Advice接口,包含了把事物加进去的逻辑。

TransactionAttributeSource虽然不是一个Pointcut,但是它被Pointcut所用,用于检测一个类的方法上是否有@Transactional注解,来确定该方法是否需要事物增强。

从下图中也可以看出这一点:

可以看到这个bean通过下面的set方法被设置进去,然后又用在了Pointcut的类里了。

整体来看,此部分的结构和功能划分还是非常清晰的。下面来逐一研究。

AOP切点

TransactionAttributeSourcePointcut类以Pointcut结尾,说明它是一个切入点,就是标识要被拦截的方法。类名的前缀部分表明了这个切入点的实现原理。

看下这个前缀是TransactionAttributeSource,它以Source结尾,说明它是一个源(即源泉,有向外提供东西的意思)。它的前缀是TransactionAttribute,即事务属性。

由此可见,这个源可以向外提供事务属性,其实就是判断一个类的方法上是否标有@Transactional注解,如果有的话还可以获取这个注解的属性(即事务属性)。

整体来说就是,Pointcut拦截住了方法,然后使用这个“源”去方法和类上获取事务属性,如果能获取到,说明此方法需要参与事务,则进行事务增强,反之则不增强。

下面这张图可以证明我们的想法:

可以看出matches方法的两个参数就是一个方法(Method)和一个类(Class<?>)。最后从方法和类上获取事务属性,再进行是否为null判断。

现在这个“源”还是个黑盒子,下面来揭开它的面纱。它的实现类是AnnotationTransactionAttributeSource,以Annotation开头,说明是基于注解实现的。

下面图是它的源码的一部分:

第一个方法从类上找事务属性,第二个方法从方法上找事务属性,它俩都调用了第三个方法来实现。

PS:我们都知道,方法上的注解优先级高于类上的,是因为找注解时先找方法上的,找不到时再去类上找。所以方法上的优先级高。此部分代码逻辑在父类里写着呢,这里不再展示了。

第三个方法使用多个事务注解解析器(TransactionAnnotationParser)去解析注解,为啥是多个解析器呢?因为事务注解不仅Spring提供了,Java后来也提供了,就是javax.transaction.Transactional。

Spring对自己注解的解析器实现类是SpringTransactionAnnotationParser,如下图:

可以看出使用工具类来读取注解@Transactional的属性,然后逐个解析出属性值并进行类型转换,接着把这些属性封装到一个类里,这个类其实就是事务属性,即TransactionAttribute。

这个事务属性继承了事务定义接口,事务定义接口我们应该都很熟悉,如下图:

这也证明了以前文章里说过的话,@Transactional注解的作用有两个,一是表明要参与事务,二是表明如何参与事务,这些注解属性就是来规定如何参与的。

这个事务属性TransactionAttribute是个接口,它的实现类在这里就不再详说了。

AOP增强

Advice就是AOP中的增强,TransactionInterceptor实现了Advice接口,所以它就是事务增强。

先来看下该接口,如下图:

发现它只是一个空的标记接口。而且它的包名是org.aopalliance,是一个AOP联盟组织,它制定的AOP规范。

先来了解下AOP领域的一些相关内容,Pointcut是切入点,表示要拦截的方法。它是一个静态的概念,即程序不运行时它也是存在的。

那么在真正运行时,已经拦截住了,此时该怎么表示这个情况呢?是用Joinpoint来表示的,所以Joinpoint是一个运行时的概念,只有在运行时才存在。

请看Joinpoint接口,如下图:

第一个方法proceed()是“继续”的意思,调用它表示去执行被拦截住的方法本身,返回方法本身的返回值。

第二个方法getThis()是获取this对象,即方法运行时所在的目标对象。如果是静态方法,则为null,因为静态方法是属于类本身的,运行时不需要对象。

第三个方法getStaticPart(),其实就表示了被拦截住的方法,即就是一个Method。Method其实算是“元数据”,是属于类型本身的,也有“静态”的意思。

再看一个接口,Invocation,它继承了Joinpoint,如下图:

方法getArguments()就表示运行时传递给被拦截住方法的参数。

再看一个接口,MethodInvocation,它继承了Invocation,如下图:

方法getMethod()返回一个Method,它就是当前正在执行的方法,是对本拦截方法的一个友好实现,返回相同的结果。

可见MethodInvocation接口已经包含了一个方法调用的全量信息,方法,参数,目标对象。这其实就是运行时被拦截住的东西。

再看下面这个接口,MethodInterceptor,方法拦截器,如下图:

它只有一个方法invoke,方法参数就是上面介绍的MethodInvocation。所以拦截器可以使用这个参数来对目标方法进行调用,当然在调用前/后可以加入自己的逻辑。

TransactionInterceptor类就实现了这个接口,因此可以在对目标方法的调用前后插入事务逻辑代码来进行事务增强。

下面是事务拦截器对该方法的实现,如下图:

它调用的invokeWithinTransaction方法是在父类里的,看下图:

这个图里做的事情较多,逐个来看:

前两行获取事务属性“源”,再用这个“源”来获取事务属性。咦,有点奇怪,上面不是已经获取过了吗?是的,上面是在Pointcut里获取的,那只是用于判断那个方法是否要被拦截而已。这里获取的属性才是真正用于事务的。

第三行是根据事务属性,来确定出一个事务管理器来。

接下来是使用事务管理器打开事务。

接下来是对被拦截住的目标方法的调用执行,当然要try/catch住这个执行。

如果抛出了异常,则进行和异常相关的事务处理,然后将这个异常继续向上抛出。

如果没有抛出异常,则进行事务提交。

最后的else分支是对编程式事务的调用,事务的打开/提交/回滚是开发人员自己写代码控制,所以就不需要事务管理器操心了。

下面请看和异常相关的事务处理,如下图:

判断异常类型是否需要回滚,需要的话就回滚事务,不需要的话就继续提交事务。

这里的整体结构和逻辑流程也是比较清晰的,那是因为一方面得益于AOP领域的概念,另一方面是事务管理器屏蔽了事务的所有复杂性。

PS:事务管理器的内容其实还是挺复杂的,下篇文章再详细解说。

好了,以上是小编给大家介绍的Spring事务面试整理,希望对大家有所帮助,如果大家有任何疑问欢迎给我留言,小编会及时回复大家的!

(0)

相关推荐

  • Spring boot jpa 删除数据和事务管理的问题实例详解

    今天我们介绍的是jpa删除和事务的一些坑,接下来看看具体内容. 业务场景(这是一个在线考试系统)和代码:根据问题的id删除答案 repository层: int deleteByQuestionId(Integer questionId); service 层: public void deleteChoiceAnswerByQuestionId(Integer questionId) { choiceAnswerRepository.deleteByQuestionId(questionId)

  • 详解Springboot事务管理

    在Spring Boot事务管理中,实现自接口PlatformTransactionManager. public interface PlatformTransactionManager { org.springframework.transaction.TransactionStatus getTransaction(org.springframework.transaction.TransactionDefinition transactionDefinition) throws org.

  • 深入理解Spring的事务传播行为

    前言 Spring在TransactionDefinition接口中规定了7种类型的事务传播行为.事务传播行为是Spring框架独有的事务增强特性,他不属于的事务实际提供方数据库行为.这是Spring为我们提供的强大的工具箱,使用事务传播行可以为我们的开发工作提供许多便利.但是人们对他的误解也颇多,你一定也听过"service方法事务最好不要嵌套"的传言.要想正确的使用工具首先需要了解工具.本文对七种事务传播行为做详细介绍,内容主要代码示例的方式呈现. 基础概念 1. 什么是事务传播行

  • Spring中事务管理的四种方法(银行转账为例)

    前言 本文配套示例代码下载地址(完整可运行,含sql文件,下载后请修改数据库配置):点击这里下载 一.事务的作用 将若干的数据库操作作为一个整体控制,一起成功或一起失败. 原子性:指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生. 一致性:指事务前后数据的完整性必须保持一致. 隔离性:指多个用户并发访问数据库时,一个用户的事务不能被其他用户的事务所干扰,多个并发事务之间数据要相互隔离. 持久性:指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,即时数据库发生故障也不应

  • 浅谈SpringBoot之事务处理机制

    一.Spring的事务机制 所有的数据访问技术都有事务处理机制,这些技术提供了API用来开启事务.提交事务来完成数据操作,或者在发生错误的时候回滚数据. 而Spring的事务机制是用统一的机制来处理不同数据访问技术的事务处理.Spring的事务机制提供了一个PlatformTransactionManager接口,不同的数据访问技术的事务使用不同的接口实现: 在程序中定义事务管理器的代码如下: @Bean public PlatformTransactionManager transaction

  • SpringBoot 注解事务声明式事务的方式

    springboot 对新人来说可能上手比springmvc要快,但是对于各位从springmvc转战到springboot的话,有些地方还需要适应下,尤其是xml配置.我个人是比较喜欢注解➕xml是因为看着方便,查找方便,清晰明了.但是xml完全可以使用注解代替,今天就扒一扒springboot中事务使用注解的玩法. springboot的事务也主要分为两大类,一是xml声明式事务,二是注解事务,注解事务也可以实现类似声明式事务的方法,关于注解声明式事务,目前网上搜索不到合适的资料,所以在这里

  • 解决spring mvc 多数据源切换,不支持事务控制的问题

    一个项目中需要使用两个数据库,Oracle 和Mysql,于是参考各个blog,实现此功能.写好后才发现,原来的事务失效了,我去... spring-mybatis.xml 配置 <bean id="configReader" class="org.springframework.beans.factory.config.PreferencesPlaceholderConfigurer"> <property name="location

  • 【面试】Spring事务面试考点吐血整理(建议珍藏)

    Starting from a joke 问:把大象放冰箱里,分几步? 答:三步啊,第一.把冰箱门打开,第二.把大象放进去,第三.把冰箱门带上. 问:实现Spring事务,分几步? 答:三步啊,第一.找出需要事务的方法,第二.把事务加进去,第三.执行事务. You may find it's not a joke, it's serious. Try to find an entrance 当你面对一个完全不熟悉的事物时,一定要想办法找到一个突破口,然后逐步深入.那Spring事物的突破口在哪里

  • 面试Spring中的bean线程是否安全及原因

    目录 SpringBean作用域 spring单例,为什么controller.service和dao确能保证线程安全? 总结 面试官经常喜欢问Spring中的bean是不是线程安全的这个问题用来考察对Spring  中Bean作用域的理解,先说结论,Spring中的Bean不是线程安全的. Spring容器中的Bean是否线程安全,容器本身并没有提供Bean的线程安全策略,因此可以说Spring容器中的Bean本身不具备线程安全的特性,但是具体还是要结合具体scope的Bean去研究. Spr

  • Spring Boot面试必问之启动流程知识点详解

    目录 一 面试提问 1.1 Spring Boot启动流程 1.2 SpringBoot自动装配 二 知识点详解 2.1 SpringBoot核心注解: 2.2详细启动流程(结合源码) 总结 一 面试提问 1.1 Spring Boot启动流程 ???面试官:说说SpringBoot启动流程吧 ?? 我 : 首先从main找到run()方法,在执行run()方法之前new一个SpringApplication对象 进入run()方法,创建应用监听器SpringApplicationRunList

  • Spring事务失效场景的详细整理

    目录 前言 数据库引擎不支持事物 方法不是 public 的 自身调用问题 不支持事物 异常被吃掉 异常类型错误 总结 前言 项目中用Spring的 @Transactional 注解控制事务,使用中时常出现事物不生效的场景,本文仅限于日常项目开发中的点滴整理总结,总结以下几点,以备后续参考排查;可能不全,列举出来希望可以帮助有需要的同学,避免踩坑. 数据库引擎不支持事物 这里以 MySQL 为例,其 MyISAM 引擎是不支持事务操作的,InnoDB 才是支持事务的引擎,一般要支持事务都会使用

  • Spring事务管理原理及方法详解

    这篇文章主要介绍了Spring事务管理原理及方法详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 事务,在日常开发或者面试中都必定会涉及到.开发工作中,结合数据库开发理解就是:一组dml要么全部成功执行提交,要么因为某一个操作异常,撤销之前所做的成功的操作,整体执行失败.再简单点的一句话:生死与共. 由此,可以看出,事务的必要性:在开发工作中,保证操作数据的安全性.事务的控制也就是保证数据的访问安全性. 一.事务的四大特性 A:原子性(ato

  • 深入理解Spring事务原理

    一.事务的基本原理 Spring事务的本质其实就是数据库对事务的支持,没有数据库的事务支持,spring是无法提供事务功能的.对于纯JDBC操作数据库,想要用到事务,可以按照以下步骤进行:  1.获取连接 Connection con = DriverManager.getConnection()  2.开启事务con.setAutoCommit(true/false);  3.执行CRUD  4.提交事务/回滚事务 con.commit() / con.rollback();  5.关闭连接

  • spring事务隔离级别、传播机制以及简单配置方式

    一.spring支持的事务声明方式 1. 编程式事务 当系统需要明确的,细粒度的控制各个事务的边界,应选择编程式事务. 2. 声明式事务 当系统对于事务的控制粒度较粗时,应该选择申明式事务,通过<tx>标签和<aop>切面形式在xml中进行配置. 3. 无论你选择上述何种事务方式去实现事务控制,spring都提供基于门面设计模式的事务管理器供选择,如下是spring事务中支持的事务管理器 事务管理器实现(org.springframework.*) 使用时机 jdbc.dataso

  • 详细谈谈Spring事务是如何管理的

    目录 前言 Spring事务抽象 PlatformTransactionManager是事务管理器接口 常见的事务管理器有以下几种 定义事务的一些参数: 7种事务传播特性: 四种事务隔离级别: Spring之编程式事务 声明式事务 为什么加了@Transactional注解事物就生效了? 通过注解怎么实现指定的传播特性和隔离级别的? 事务失效的8种情况及解决办法 总结 前言 我们都知道Spring给我们提供了很多抽象,比如我们在操作数据库的过程中,它为我们提供了事务方面的抽象,让我们可以非常方便

  • 一篇文章带你了解spring事务失效的多种场景

    目录 前言 一 事务不生效 1.访问权限问题 2. 方法用final修饰 3.方法内部调用 4.未被spring管理 5.多线程调用 6.表不支持事务 7.未开启事务 二 事务不回滚 1.错误的传播特性 2.自己吞了异常 3.手动抛了别的异常 4.自定义了回滚异常 5.嵌套事务回滚多了 三 其他 1 大事务问题 2.编程式事务 总结 前言 对于从事java开发工作的同学来说,spring的事务肯定再熟悉不过了. 在某些业务场景下,如果一个请求中,需要同时写入多张表的数据.为了保证操作的原子性(要

  • Java spring事务及事务不生效的原因详解

    目录 注解 @Transactional 的属性参数 propagation 事务的传播机制 isolation 事务的隔离级别 常用数据库的默认隔离级别 readOnly 事务的读写性 事务的只读性概念 应用场景 timeout 超时时间 rollbackFor 和 rollbackForClassName 遇到时回滚 noRollbackFor 和 noRollbackForClassName 遇到时不回滚 value 指定使用的事务管理器 spring 事务不生效的原因 数据库引擎不支持事

随机推荐