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

标签:SpringBoot,异步,事务
0
投稿

猜你喜欢

  • JAVA ArrayList详细介绍(示例)

    2023-02-18 22:30:56
  • C#关于Func和Action委托的介绍详解

    2022-10-13 04:43:14
  • Java的Socket网络编程基础知识入门教程

    2021-11-19 10:10:37
  • SpringBoot下使用定时任务的方式全揭秘(6种)

    2022-06-13 01:34:48
  • 使用JMF实现java视频播放器

    2022-12-26 00:28:25
  • Android继承现有控件拓展实现自定义控件textView

    2021-05-29 06:29:15
  • 2020最新eclipse安装过程及细节

    2023-11-06 09:25:56
  • springboot项目以jar包运行的操作方法

    2023-11-10 07:47:43
  • Android中退出确认框的实现代码

    2022-02-23 06:40:31
  • C#中Socket通信用法实例详解

    2022-07-10 03:42:03
  • Android使用shape使组件呈现出特殊效果的方法

    2022-06-28 03:42:27
  • IntelliJ IDEA 如何配置git的操作方法

    2021-12-28 11:24:44
  • Android RIL使用详解

    2021-09-30 18:06:45
  • Java基础之从HelloWorld到面向对象

    2022-11-23 11:55:06
  • springcloud-gateway集成knife4j的示例详解

    2023-11-29 08:56:44
  • Springboot 内部服务调用方式

    2023-08-24 00:32:20
  • 浅谈java的接口和C++虚类的相同和不同之处

    2023-08-05 12:01:51
  • Druid(新版starter)在SpringBoot下的使用教程

    2021-07-03 20:25:18
  • 浅析Java设计模式编程中的单例模式和简单工厂模式

    2021-10-13 15:27:54
  • Android实现分享长图并且添加全图水印

    2021-08-04 19:30:57
  • asp之家 软件编程 m.aspxhome.com