事务执行基本流程与一次事务失效分析

0. 业务背景

在事务使用时,由于对事务的运行机制不了解,记得有一次在事务使用时,错误的由类的非事务方法调用类自身的事务方法,导致异常回滚失败,事务失效。借此熟悉了下事务的基本流程,同时分析了事务失效的原因。

1. 事务基本流程

事务的基本流程分为2个部分:

  1. 创建代理对象
  • 在创建完reportServiceImpl这个bean之后,进行bean的后置处理。主要是基于ProxyCreator这个处理器来创建代理对象。
  • 通过循环reportServiceImpl这个目标类上面的method,解析缓存method上面的事务属性,如果method上面有事务属性,则代表此切面(增强器)可以使用在目标类上面,因此匹配到bean可以使用的切面(增强器)。
  • 基于匹配到切面,来创建代理对象。
  • 最后缓存代理对象到单例cache中。

注:这个切面 里面包含了:切点、拦截器(也就是业务方法的增强处理逻辑。后面会说明)。

  1. 执行事务
  • context上下文获取代理对象
  • 执行业务方法之前,代理对象调用interceptor拦截器的拦截方法
  • 拦截里面的业务逻辑:获取业务方法上面的事务属性、创建事务、执行目标方法、异常回滚

2. 原理分析

1. 创建reportServiceImpl这个bean

refresh方法入口

从单例cache中获取名为"reportServiceImpl"单例bean为null,所以调用createBean来创建bean

创建bean

2. bean的后置处理

处理bean

主要逻辑就是创建代理

2.1 返回系统缓存的事务属性增强器

这个增强器应该理解为切面。

2.2 匹配bean可以使用的切面(增强器)

循环目标类的method

校验方法为public

解析得到事务属性

返回方法上面的事务属性

缓存method->事务属性的映射关系,并返回事务属性。

代码依次返回,直到回到matcher逻辑的这段代码。发现查询目标类的org.example.transaction.service.ReportServiceImpl.generateUseTransactional()方法有事务注解,则返回true

目标类上有method有事务属性,则保存这个切面并返回。

代码依次返回,最后返回目标类上面可以使用的切面

2.3 基于切面创建代理对象

代理工厂指定切面和目标对象

生成代理对象

使用enhancer创建代理对象,父类指向目标类。

创建代理对象,设置回调(即切面里面的拦截器,也就是增强逻辑)

返回到前面的wrapIfNecessary方法,返回代理对象

ProxyCreator处理器处理之后,创建并返回代理对象

流程回到initBean方法,得到代理对象并返回到上层。

继续返回代理对象

3. 缓存代理对象到单例cache中

回到getSingleton方法,接收创建的bean(实际上是代理对象),并缓存到单例cache中。

代理对象 添加到单例的map中

4. context上下文获取代理对象

从上面缓存的单例map中获取代理对象

继续返回代理对象,直到context得到代理对象

5. 执行事务

回到我们最开始的代码,通过目标对象的代理对象 执行业务方法

代理对象会调用拦截器的拦截方法,这个拦截方法也就是切面里面业务方法的增强处理逻辑。

在intercept方法中调用proceed方法

调用事务拦截器

5.1 获取目标业务方法上面的事务属性

5.2 创建事务

【注意】:生成事务的条件。

创建事务对象 ,持有的connection为null

开启事务

获取连接,为事务对象设置连接。

关闭自动提交

dataSource数据源->connect映射关系 绑定到当前线程

设置事务隔离级别,默认。同时激活当前线程的事务同步。

包装事务信息并绑定到当前线程

5.3 执行目标类中的业务方法

执行到了业务方法中了

5.4. 如果异常会执行回滚

检查异常是否是事务属性定义的异常

执行回滚

连接执行回滚

3. 类的非事务方法调用自身的事务方法,事务会失效原因分析

执行非事务注解的业务方法generate()

首先代理对象执行拦截处理,获取可用于generate方法的拦截器

获取method上是否有事务注解属性

很显然没有事务注解,所以返回的拦截器为空

所以不会创建事务,更不会执行回滚。

最终generate方法调用saveReport方法都是以非事务方式运行,所以抛出异常不会回滚。

相关推荐
.生产的驴37 分钟前
SpringCloud Gateway网关路由配置 接口统一 登录验证 权限校验 路由属性
java·spring boot·后端·spring·spring cloud·gateway·rabbitmq
提高记忆力1 小时前
SpringBoot整合FreeMarker生成word表格文件
java·spring
wclass-zhengge8 小时前
SpringCloud篇(配置中心 - Nacos)
java·spring·spring cloud
黑马师兄8 小时前
SpringBoot
java·spring
LuckyLay10 小时前
Spring学习笔记_34——@Controller
spring·controller
ApiHug12 小时前
ApiSmart x Qwen2.5-Coder 开源旗舰编程模型媲美 GPT-4o, ApiSmart 实测!
人工智能·spring boot·spring·ai编程·apihug
背水12 小时前
初识Spring
java·后端·spring
闲人一枚(学习中)13 小时前
spring -第十四章 spring事务
java·数据库·spring
wclass-zhengge13 小时前
SpringCloud篇(注册中心 - Eurea)
后端·spring·spring cloud
小蒜学长15 小时前
springboot基于SpringBoot的企业客户管理系统的设计与实现
java·spring boot·后端·spring·小程序·旅游