解决主线程提交事务导致异步方法执行失败解决方法

业务场景:异步线程需要根据主线程执行后保存在数据库的结果,去执行异步操作。由于数据库的隔离机制,可能会导致异步线程没有读取到主线程保存的最新的数据。

解决办法:主线程执行完毕提交完事务后发布消息,然后触发一个event(事件)。异步线程进行监听,监听主线程发布的事件,接受到后再去执行异步的逻辑。

代码demo

1. 定义事件类
首先,定义一个自定义事件类,继承 ApplicationEvent。

import org.springframework.context.ApplicationEvent;

public class MyCustomEvent extends ApplicationEvent {
    private final String message;

    public MyCustomEvent(Object source, String message) {
        super(source);
        this.message = message;
    }

    public String getMessage() {
        return message;
    }
}

2. 发布事件
在主线程中,使用 ApplicationEventPublisher 发布事件。确保事件在主线程事务提交后发布。

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
public class MyService {

    @Autowired
    private ApplicationEventPublisher eventPublisher;

    @Transactional
    public void mainThreadMethod() {
        // 执行数据库操作
        someRepository.save(someEntity);

        // 发布事件
        eventPublisher.publishEvent(new MyCustomEvent(this, "事务已提交"));
    }
}

3. 监听事件
使用 @TransactionalEventListener 监听事件,并确保事件在主线程事务提交后触发。


import org.springframework.stereotype.Component;
import org.springframework.transaction.event.TransactionPhase;
import org.springframework.transaction.event.TransactionalEventListener;

@Component
public class MyEventListener {

    @TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
    public void handleMyCustomEvent(MyCustomEvent event) {
        // 处理事件
        System.out.println("收到事件: " + event.getMessage());
    }
}

启用异步支持:
在 Spring Boot 主类或配置类上添加 @EnableAsync 注解。

import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
@EnableAsync
public class MyApplication {
    public static void main(String[] args) {
        SpringApplication.run(MyApplication.class, args);
    }
}

最后测试调用主线程执行方法 是否是在主线程事务提交后触发

注:

   1.如果需要异步方法执行后的返回结果

  • 如果异步方法需要返回值,可以使用 Future 或 CompletableFuture
  • 示例
    @Async
    public CompletableFuture<String> asyncMethodWithReturn() {
        return CompletableFuture.completedFuture("异步方法返回值");
    }
    

    2.Spring 事件监听器自带线程池(如果异步操作较多可以考虑配置异步的线程池)

  • 阻塞场景:默认的 Spring 事件机制(同步执行),同步调用耗时方法

  • 不阻塞场景:使用@Async注解的异步方法,使用Spring机制并结合@Async注解

  • 如果不配置线程池,Spring 会使用默认的 SimpleAsyncTaskExecutor,它会为每个任务创建一个新线程,可能导致线程数量过多,资源耗尽。可以限制线程数量并复用线程,提升性能和稳定性。
@Configuration
@EnableAsync
public class AsyncConfig implements AsyncConfigurer {

    @Override
    public Executor getAsyncExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(10); // 核心线程数
        executor.setMaxPoolSize(50);  // 最大线程数
        executor.setQueueCapacity(100); // 队列容量
        executor.setThreadNamePrefix("Async-");
        executor.initialize();
        return executor;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值