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

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方法都是以非事务方式运行,所以抛出异常不会回滚。

相关推荐
卓怡学长28 分钟前
w272基于springboot便民医疗服务小程序
java·spring boot·spring·小程序·intellij-idea
霸道流氓气质32 分钟前
Harness Engineering 从理论到实战:基于 Spring AI Alibaba 的完整实现指南
数据库·人工智能·spring·harness
AI人工智能+电脑小能手19 小时前
【大白话说Java面试题 第155题】【06_Spring篇】第15题:Spring 如何解决循环依赖问题?
java·spring·循环依赖·三级缓存·aop代理
AI人工智能+电脑小能手1 天前
【大白话说Java面试题 第156题】【06_Spring篇】第16题:Spring 用到了哪些设计模式?
java·spring·设计模式·代理模式·工厂模式
辰海Coding1 天前
MiniSpring框架学习笔记-动态代理:如何在运行时插入逻辑?
java·笔记·学习·spring·动态代理
一路向北North1 天前
Spring Security OAuth2.0(16):密码模式
java·后端·spring
卓怡学长1 天前
w273基于springboot的智能笔记的开发与应用
java·spring boot·spring·intellij-idea
无心水2 天前
【全域智能营销实战】2、Spring AI 模块化架构深度解读:从 1.0 到 2.0 的演进与最佳实践
人工智能·spring·架构·harness·顶尖架构师·全域智能营销·harmess
livemetee2 天前
【关于Spring声明式事务】
java·后端·spring
Esaka_Forever2 天前
Python 完整内存管理机制详解
开发语言·python·spring