likes
comments
collection
share

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

作者站长头像
站长
· 阅读数 6

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

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

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