SpringBoot异步与事务一起使用的问题解决
作者:ghimi 发布时间:2023-03-17 07:11:08
最近遇到的一个场景,在一个被 @Transactional 注解的方法A中中调用了一个被 @Async 注解标记的方法B,由于方法B 在执行时方法A 的事务没有提交,但是方法B在执行过程中获取不到方法A中尚未提交的数据,从而最终倒是方法B执行异常。
@Transactional
public void create(User user){
// 如果用户已存在,则先删除
delete(user.id);
// 创建用户
int userId = insert(user);
// 更新用户信息
update(userId);
}
@Async
public void update(Integer userId){
Icon icon = getUserIcon(userId);
// 更新用户图片
updateUserPohot(userId,icon);
}
像上面的代码,我为创建用户的方法上标记了@Transactional事务注解,然后在其中调用了update()更新方法,这个方法上标记了@Async 注解。这样代码虽然看起来没有什么问题,但是实际在执行update()方法时,由于是其他线程去执行的,就会导致有可能 create()方法对应的事务还没有提交,update() 方法就无法读取到新插入的 user 记录,从而导致更新失败。
解决方案
通过调整逻辑保证事务在调用异步方法前被提交
这个问题的原因是由于 @Transactional 和 @Async 注解一起使用导致的,那么我们可以从这个方向入手,首先我们可以先确认将create()方法的事务提交后,然后再去执行异步更新方法:
public void create(User user){
int userId = doCreate(user);
// 更新用户信息
update(userId);
}
@Transactional
public void doCreate(User user){
// 如果用户已存在,则先删除
delete(user.id);
// 创建用户
return insert(user);
}
@Async
public void update(Integer userId){
Icon icon = getUserIcon(userId);
// 更新用户图片
updateUserPohot(userId,icon);
}
异步方法放在事务方法外调用,这样异步方法就能够读取到已经提交的事务数据了。
或者我们还可以使用TransactionTemplate来代替 @Transactional 注解:
@Autowired
TransactionTemplate transactionTemplate;
public void create(User user){
int userId = transactionTemplate.execute(status->{
// 如果用户已存在,则先删除
delete(user.id);
// 创建用户
return insert(user);
});
// 更新用户信息
update(userId);
}
@Async
public void update(Integer userId){
Icon icon = getUserIcon(userId);
// 更新用户图片
updateUserPohot(userId,icon);
}
通过 TransactionTemplate细化了事务粒度,可以保证在调用异步方法前事务已经被提交。
上面的方案基本都能 解决问题,下面是从网上找到的,spring 给出的解决方案:
@Transactional
public void create(User user){
// 如果用户已存在,则先删除
delete(user.id);
// 创建用户
int userId = insert(user);
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
@Override
public void afterCommit() {
// 更新用户信息
update(userId);
}
});
}
@Async
public void update(Integer userId){
Icon icon = getUserIcon(userId);
// 更新用户图片
updateUserPohot(userId,icon);
}
通过将异步方法注册为事务提交后的操作,这样Spring可以自动帮我们在事务提交后执行对应的操作。
参考资料
异步事务?关于异步@Async + 事务
@Transactional 事务提交 与 @Async 异步执行
来源:https://blog.csdn.net/qq_19922839/article/details/126322800


猜你喜欢
- Toast一般用来显示一行文字,用法比较固定:Toast.makeText(Context context,String message,i
- 目标:双向拖动的自定义View国际惯例先预览后实现我们要实现的就是一个段位样式的拖动条,用来做筛选条件用的,细心的朋友可能会发现微信设置里面
- 本文实例为大家分享了Android SeekBar实现平滑滚动的具体代码,供大家参考,具体内容如下由于项目需要,SeekBar只需要三个档,
- 介绍上图就是循环依赖的三种情况,虽然方式不同,但是循环依赖的本质是一样的,就A的完整创建要依赖与B,B的完整创建要依赖于A,相互依赖导致没办
- java语言里包含了许多对设计模式的直接支持,如command模式,agent模式,observer模式等。虽然java提供的对
- springboot部署项目在linux的两种方式 可以选择 war包方式或者jar包方式(个人推荐使用jar方式)1.springboot
- 在字符集中,有一类字符具有这样的特性:当从键盘上输入这个字符时,显示器上就可以显示这个字符,即输入什么就显示什么。这类字符称为可显示字符,如
- 目前html5发展非常迅速,很多native app都会嵌入到网页中,以此来适用多变的市场需求。但是android的webview默认支持的
- //构造文件File类File f=new File(fileName);//判断是否为目录f.isDirectory();//获取目录下的
- switch语句的格式如下:(它的功能是选出一段代码执行) switch(整数选择因子) { case 整数值1 : 语句; break;
- 一、java内存区域Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干个不同的数据区域。这些区域都有各自的用途,以及创建和
- 发送邮件的主程序 import java.util.Properties; import common.util.Ema
- 目录一对一关联保存:留言表实体类配置:(主表)留言内容表配置:(从表)留言表hbm.xml配置:(主表)留言内容表hbm.xml配置:(从表
- 一、概述之前公司app里面有个功能是一个可以双向滑动的范围选择器,我在网上百度过一些实现方法,感觉各有利弊吧,但是都不太适合我们的需求。所以
- 开源配置中心 - ApolloApollo(阿波罗)是携程框架部门研发的配置管理平台,能够集中化管理应用不同环境、不同集群的配置,配置修改后
- 前言:在日常的代码开发中,此处相信每个开发人员对代码质量都是高要求,有自己的一套代码规范,但是我们不是单独作战,往往大家都是团队作战,人是最
- 实例如下:/** * 将一个list均分成n个list,主要通过偏移量来实现的 * @param source * @return */ p
- 本文实例讲述了Android实现捕获TextView超链接的方法。分享给大家供大家参考,具体如下:这里分享一篇捕获TextView超链接的文
- 一、项目简述本系统功能包括: 一款基于Springboot+Vue的电商项目,前后端分离项目,前台后台都有,前台商品展示购买,购物车分类,订
- 概述对List进行分组是日常开发中,经常遇到的,在JDK 8中对List按照某个属性分组的代码,超级简单。package test;impo