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
猜你喜欢
- 一、堆的概念堆的定义:n个元素的序列{k1 , k2 , … , kn}称之为堆,当且仅当满足以下条件时:(1)ki
- 本文实例讲述了C++实现的O(n)复杂度内查找第K大数算法。分享给大家供大家参考,具体如下:题目:是在一组数组(数组元素为整数,可正可负可为
- 在看别人的关于CopyOnWriteArrayList 这个类的时候,看到有人提出了关于:数组拷贝的方法Arrays.copyOf() 的问
- 本文以实例形式讲述了C#泛型的用法,有助于读者深入理解C#泛型的原理,具体分析如下:首先需要明白什么时候使用泛型:当针对不同的数据类型,采用
- 1、dose not point to a valid jvm installation出错问题按照以下方法设置一定可以不会出现这个错误。我
- Android 消息机制1.概述Android应用启动时,会默认有一个主线程(UI线程),在这个线程中会关联一个消息队列(MessageQu
- #include<iostream>using namespace std;//非递归求解所有的子集void fun(int a
- 问题描述:1. 项目集成WebSocket,且打包发布tomcat时出现websocket is already in CLOSING or
- 本文实例讲述了Winform下实现图片切换特效的方法,是应用程序开发中非常实用的一个功能。分享给大家供大家参考之用。具体方法如下:本实例源自
- 目录Directory:创建文件夹删除文件夹获取文件夹下的子文件夹获取同类型的文件判断文件夹是否存在移动文件夹总结之前发过File对文件的操
- 定义里氏替换原则(Liskov Substitution Principle,LSP),官方定义如下: 如果对每一个类型为S的对象o1,都有
- 这篇文章主要介绍了java获取当前时间并格式化代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋
- 本文实例为大家分享了java实现简单年龄计算器的具体代码,供大家参考,具体内容如下制作一个如下图年龄计算器根据题目,我做了一个由Calend
- 引言我已经一个多星期没碰过电脑了,今日上班,打开电脑的第一件事就是想着写点什么。反正大家都还沉浸在节后的喜悦中,还没进入工作状态,与其浪费时
- 写在前面从Java 1.0开始,引入java.io包;到Java 1.4再扩展了java.nio包;再到java 1.7又添加了新的流类,使
- 1、问题描述关于java中的日志管理logback,去年写过关于logback介绍的文章,这次项目中又优化了下,记录下,希望能帮到需要的朋友
- 原始Spring开发Person.java准备Person.java类:package com.jektong.spring;public
- MD5,全称为 Message Digest Algorithm 5(消息摘要算法第五版).详情请参考 * :MD5MD5加密后是一个字
- 在整合SpringBoot和Mybatis-plus时,想写自定义的sql,所以创建了Mapper.xml文件,但是启动后却老是报错:org
- 最近学习JavaFx,发现网上大概只有官方文档可以查阅,学习资料较少,写个拼图游戏供记录。。大概说一下思路:1.面板的构建:面板采用Grid