背景
最近在写一个业务实现:主线程生成订单,然后使用自定义 AOP 的 @AfterReturning
注解,通过新建线程异步查询该条订单并推送到其他系统。
开发环境中,整个流程执行一直没问题(重复测试了很多遍)。一放到线上,问题就出来了。异步查询这一步,在线上一直查不到新生成的这条订单。但主线程返回后会调起支付,在支付业务中能正常查到。(.............莫名其妙的bug)
分析
当前环境(线上/线下)
- 数据库为默认事务隔离级别
REPEATABLE-READ
可重复读。 - Spring 中开启了事务。
问题产生原因
- 主线程与异步子线程不属于同一个事务。
Spring的事务是通过ThreadLocal来保证线程安全的,使用ThreadLocal来存储Connection,不同的线程Connection不一样,所以不在同一个事务中。
- 在主线程事务未提交时,异步子线程无法读取到主线程事务中的数据。
为什么线下开发环境中没有出现问题?
自我分析:极有可能是线下开发环境中,机器执行速度较慢,每次执行到异步子线程中查询前,主线程都已经提交了事务;而线上机器执行速度快,执行异步子线程查询操作时,主线程还未提交事务,导致查询不存来。
解决问题
主要思路
- 控制事务范围,即使主线程中事务在自定义 AOP 执行之前,提交事务。
- Spring 中事务也是使用 AOP 来控制的,通过设置
order值
来控制,切面加载顺序。 -
order
值越大,优先级越小,反之越大。
order取值范围
package org.springframework.core;
public interface Ordered {
int HIGHEST_PRECEDENCE = -2147483648; // 2^31
int LOWEST_PRECEDENCE = 2147483647; // 2^31 - 1
int getOrder();
}
注:其实所有切面order值
不能取到最高优先级,会报错
java.lang.IllegalStateException: No MethodInvocation found: Check that an AOP invocation is in progress,
and that the ExposeInvocationInterceptor is upfront in the interceptor chain. Specifically,
note that advices with order HIGHEST_PRECEDENCE will execute before ExposeInvocationInterceptor!
ExposeInvocationInterceptor
是一个调用器的拦截器,打开起源吗可以看到
@Override
public int getOrder() {
return PriorityOrdered.HIGHEST_PRECEDENCE + 1; //即-2147483648+1
}
所有AOP切面(包括事务)优先级在这个值之前都会报错,所以order值
设置应大于该值
自定义 AOP 切面类中注解设置加载顺序
@Component
@Aspect
@Order(-200)
public class McGoodsAop {
}
注:初步测试,@Order注解写在方法中,不生效
Springboot中设置事务加载优先级
@SpringBootApplication
@EnableTransactionManagement(order = 0) // order = 0 设置事务加载优先级
public class ApiApplication {
public static void main(String[] args) {
SpringApplication.run(ApiApplication.class, args);
}
}
总结
1. order值
设置的是加载顺序,如事务优先级大于自定义 AOP 切面,则 AOP 切面内业务将被包含在事务中,可控制事务回滚等;如事务优先级小于自定义 AOP 切面,则在执行自定义AOP中代码时,事务已经完成(提交)。
2. 事务和自定义AOP默认优先级(不主动设置)均为最低级,优先级相同情况下,以事务 AOP 优先。
3. 因为用的是返回通知@AfterRunning
,刚开始以为事务优先级高会在执行自定义 AOP 中代码前提交事务(这是错误的),导致耽误了不少时间。
4. 事务和自定义 AOP 修改order值
,热部署都不生效,需要重启应用。
order优先级补充
通过aop编写的代码会在运行时进行织入(动态代理),织入的过程类似于方法调用,是一个入栈出栈的过程。

网友评论