首页 > 其他分享 >问:@Async和@Transaction可以一起使用吗?

问:@Async和@Transaction可以一起使用吗?

时间:2024-08-05 20:28:22浏览次数:7  
标签:异步 Transaction private 线程 一起 注解 Async public

 

 在Java中,@Async 和 @Transaction注解是可以一起使用的,但需要注意一些细节和潜在问题。

 

1. @Async 和 @Transactions 注解

  @Async注解:用于异步执行方法。使用此注解的方法会在单独线程中执行,而不会阻塞调用线程。在需要执行耗时操作而不希望阻塞主线程时非常有用。

 

  @Transactional注解:用于声明方法的事务性,通常用于数据库的操作,以确保方法的执行具有原子性。事务可以控制多个数据库操作的提交和回滚,以确保数据的一致性。

 

  一起使用注意事项:

   1) 异步方法是在独立的线程中执行的,而事务是与线程绑定的。故,@Async 注解的方法通常不会继承调用方线程的事务上下文。

    若想在异步方法中使用事务,需要在异步方法内重新开启一个新的事务(重新定义 @Tranactional)。

   2) 需要确保异步方法通过 Spring 代理调用,不能再同一个类中直接调用,否则异步机制起不到作用。需要通过 Spring 容器获取的 Bean 来调用这些方法。

 

2. 示例代码

  场景:需要从数据库读取数据,进行处理,然后将结果异步返回保存数据库。

    设:从程序中读取用户数据,进行处理数据,然后异步将结果保存到另一个表中。(希望数据处理在事务中完成,以确保数据一致性,但希望保存操作是异步的,以提高性能。)

  1) 实体类(用户和处理后的结果实体类)

@Entity
@Date
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;
    private String email;
}
@Entity
@Date
public class ProcessedResult {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private Long userId;
    private String resultData;
}


  2) 定义两个仓库接口,访问数据库

@Mapper
public interface UserMapper extends BaseMapper<User> {
}

@Mapper
public interface ProcessedResultMapper extends BaseMapper<ProcessedResult> {
}

  

  3) 服务类中,结合 @Transactional 和 @Async 注解实现业务逻辑。

@Service
public class UserService {

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private ProcessedResultMapper processedResultMapper;

    @Autowired
    private AsyncService asyncService;

    @Transactional
    public void processUsers() {
        // 获取所有用户
        List<User> users = userMapper.selectList(null);

        for (User user : users) {
            // 数据处理
            String resultData = processData(user);

            // 异步保存处理结果
            asyncService.saveProcessedResult(user.getId(), resultData);
        }
    }

    private String processData(User user) {
        // 数据处理逻辑
        return "Processed data for user: " + user.getName();
    }
}

 

  4) 异步服务类。使用 @Async 注解异步保存结果。

@Service
public class AsyncService {

    @Autowired
    private ProcessedResultMapper processedResultMapper;

    @Async
    @Transactional
    public void saveProcessedResult(Long userId, String resultData) {
        // 创建并保存处理结果
        ProcessedResult processedResult = new ProcessedResult();
        processedResult.setUserId(userId);
        processedResult.setResultData(resultData);
        processedResultMapper.insert(processedResult);

        System.out.println("保存 processed result 的 user ID: " + userId);
    }
}

 

  5) 确保在配置类中启用异步支持。

@Configuration
@EnableAsync

public class AsyncConfig {

    /**
     * 定义一个线程池执行器,用于执行标记了 @Async 注解的异步方法。
     * 
     * @return Executor 线程池执行器实例
     */
    @Bean
    public Executor taskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(2);    // 核心线程数
        executor.setMaxPoolSize(5);    // 最大线程数
        executor.setQueueCapacity(500);    // 任务队列的容量
        executor.setThreadNamePrefix("AsyncThread-");    // 线程池中线程的名称前缀
        executor.initialize();    // 初始化线程池
        return executor;
    }
}

 

  执行流程:

   UserService.processUsers() 方法使用 @Transactional 注解,确保在读取和处理用户数据时的事务一致性。
   处理每个用户,结果通过 AsyncService.saveProcessedResult() 方法异步保存。同时使用 @Transactional 注解,故每次保存操作都在独立的事务内执行。
   而 saveProcessedResult 方法时异步的,因此不阻塞主线程,从而提高了性能。


3. 总结

  1) @Transactional 注解主要用于确保数据一致性和操作的原子性。@Async 注解用于提到性能。结合注解使用,需注意事务的上下文的边界和线程的管理。

  2) 为了获取性能和一致性,需要在异步方法内部定义新的事务。

 

标签:异步,Transaction,private,线程,一起,注解,Async,public
From: https://www.cnblogs.com/warmNest-llb/p/18341131

相关文章

  • Flask 用户身份验证包括登录、注册和谷歌登录未集成在一起
    https://www.freecodecamp.org/news/how-to-setup-user-authentication-in-flask/我已经使用上面的链接进行了基本的用户身份验证,但我无法添加谷歌登录。我已经尝试了很多次,但我无法添加谷歌登录。任何人都可以帮我做这个吗?问题是有src_init_.py和man......
  • Python 请求 POST 请求与 websockets 库一起使用时挂起
    我使用Python中的requests库发送POST请求,同时维护与websockets库的WebSocket连接:importasyncioimportrequestsimportwebsocketsasyncdefwebsocket_handler(uri):asyncwithwebsockets.connect(uri)aswebsocket:whileTrue:me......
  • 百度飞桨paddle提供李宏毅的《机器学习》课程、可以使用免费算力一键运行项目,快来一起
    李宏毅的课程《机器学习》是一门深入浅出、内容丰富的在线课程,由台湾大学李宏毅教授主讲。我正在AIStudio学习『李宏毅课程-机器学习』,还可以使用免费算力一键运行项目,快来一起学习吧。点击进入一、课程概述李宏毅的《机器学习》课程旨在通过生动的讲解和丰富的实例,帮助......
  • await 调用的函数不一定必须是 async 函数。 await 关键字通常用于 async 函数内部,用
    await调用的函数不一定必须是async函数。 await关键字通常用于async函数内部,用来等待一个Promise对象的解决。但如果被await调用的对象不是Promise,那么它会被直接返回。 functionnotPromiseFunction(){return42;}asyncfunctionexample(){const......
  • 我如何在 asyncio 中使用请求?
    我想在asyncio中执行并行http请求任务,但我发现python-requests会阻塞asyncio的事件循环。我找到了aiohttp但是它无法提供使用http代理的http请求服务。所以我想知道是否有办法借助||来进行异步http请求|。asyncio.你可以使......
  • Spring-transaction 事务
    1.事务介绍1.1简介事务,就是一组操作数据库的动作集合。事务是现代数据库理论中的核心概念之一。如果一组处理步骤或者全部发生或者一步也不执行,我们称该组处理步骤为一个事务。当所有的步骤像一个操作一样被完整地执行,我们称该事务被提交。由于其中的一部分或多步执行失败,导致......
  • Python:指定与继承一起使用的类方法的返回类型
    我一直在尝试了解如何在Python中指定类方法的返回类型,以便即使对于子类也能正确解释它(例如在我的Sphinx文档中)。假设我有:classParent:@classmethoddefa_class_method(cls)->'Parent':returncls()classChild(Parent):pass什么如......
  • 如何在没有元类冲突的情况下将泛型类型与 PyQt 子类一起使用?
    我已经尝试过使用sip包装类型,并且当使用abc.ABCMeta进行子类化时效果很好。abc.ABC但它不适用于classQABCMeta(wrappertype,ABCMeta):passclassWidgetBase(QWidget,metaclass=QABCMeta):...classInterfaceWidget(WidgetBase,ABC):......
  • async void 和async Task 有什么区别? 何时使用void
    在C#中,asyncvoid和asyncTask用于定义异步方法,但它们之间有一些重要的区别。下面我将详细解释这两种方法签名的区别以及何时使用它们。asyncTask定义:asyncTask方法返回一个Task对象,表示一个异步操作的完成状态。这种方法签名通常用于异步方法,它可以返回一个Task......
  • Springboot 解决mongodb transaction WriteConflict问题
     参考原文:  https://segmentfault.com/a/1190000040457995?sort=newest问题:  使用Mongodb的事务:pringframework.data.mongodb.UncategorizedMongoDbException:Commandfailedwitherror112(WriteConflict):'WriteConflict'WriteConflicterror:thisoperationco......