news 2026/7/13 22:54:49

SpringBoot @Async 异步任务与 @Transactional 事务实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
SpringBoot @Async 异步任务与 @Transactional 事务实战

异步任务和事务管理是 SpringBoot 中两个非常重要但又容易出错的特性。这篇把它们的核心用法和常见坑一次讲清楚。

一、@Async 异步任务

1. 开启异步

@SpringBootApplication@EnableAsync// 开启异步任务publicclassSeckillApplication{publicstaticvoidmain(String[]args){SpringApplication.run(SeckillApplication.class,args);}}

2. 配置线程池

@ConfigurationpublicclassAsyncConfig{@Bean("taskExecutor")publicExecutortaskExecutor(){ThreadPoolTaskExecutorexecutor=newThreadPoolTaskExecutor();executor.setCorePoolSize(5);// 核心线程数executor.setMaxPoolSize(10);// 最大线程数executor.setQueueCapacity(100);// 队列容量executor.setKeepAliveSeconds(60);// 空闲线程存活时间executor.setThreadNamePrefix("async-");executor.setWaitForTasksToCompleteOnShutdown(true);executor.setRejectedExecutionHandler(newThreadPoolExecutor.CallerRunsPolicy());executor.initialize();returnexecutor;}}

3. 使用 @Async

@ServicepublicclassSeckillAsyncService{privatestaticfinalLoggerlog=LoggerFactory.getLogger(SeckillAsyncService.class);/** * 异步发送通知 */@Async("taskExecutor")publicvoidsendNotification(LonguserId,Stringmessage){log.info("异步发送通知给用户 {}, 线程: {}",userId,Thread.currentThread().getName());// 模拟耗时操作try{Thread.sleep(2000);}catch(InterruptedExceptione){Thread.currentThread().interrupt();}log.info("通知发送完成");}/** * 异步记录日志 */@Async("taskExecutor")publicvoidrecordLog(Stringoperation,Stringdetail){log.info("记录操作日志: {} - {}",operation,detail);}}

4. @Async 的使用场景

@ServicepublicclassOrderService{@AutowiredprivateSeckillAsyncServiceasyncService;publicOrdercreateOrder(OrderDTOdto){// 1. 主流程:同步创建订单Orderorder=doCreateOrder(dto);// 2. 副流程:异步执行,不影响主流程asyncService.sendNotification(order.getUserId(),"下单成功");asyncService.recordLog("createOrder",order.getOrderNo());returnorder;}}

5. @Async 的返回值

/** * 异步方法可以返回 void 或 Future * 如果需要获取异步结果,使用 Future */@Async("taskExecutor")publicFuture<String>processAsync(LongorderId){try{Thread.sleep(3000);returnAsyncResult.forResult("处理完成: "+orderId);}catch(InterruptedExceptione){returnAsyncResult.forExecutionException(e);}}// 调用Future<String>future=asyncService.processAsync(orderId);Stringresult=future.get();// 阻塞等待结果

二、@Transactional 事务

1. 事务的 ACID 特性

原子性(Atomicity):事务中的所有操作要么全成功,要么全回滚 一致性(Consistency):事务前后数据保持一致 隔离性(Isolation):并发事务互不干扰 持久性(Durability):提交后数据永久保存

2. 基本使用

@ServicepublicclassOrderServiceImplextendsServiceImpl<OrderMapper,Order>implementsOrderService{/** * 创建订单 + 扣减库存 * 两个操作必须在一个事务中,要么都成功,要么都失败 */@Override@Transactional(rollbackFor=Exception.class)publicOrdercreateOrder(OrderDTOdto){// 1. 创建订单Orderorder=newOrder();order.setUserId(dto.getUserId());order.setProductId(dto.getProductId());order.setAmount(dto.getAmount());save(order);// 2. 扣减库存productService.deductStock(dto.getProductId(),1);returnorder;}}

3. 事务传播行为

/** * 事务传播行为:当一个事务方法调用另一个事务方法时,如何处理 */@ServicepublicclassPayService{/** * REQUIRED(默认):支持当前事务,如果不存在则创建新事务 * SUPPORTS:支持当前事务,如果不存在则以非事务方式执行 * REQUIRES_NEW:创建新事务,挂起当前事务 * NESTED:嵌套事务(JDBC 的 Savepoint 机制) * NEVER:以非事务方式执行,如果有事务则抛异常 */@Transactional(propagation=Propagation.REQUIRES_NEW)publicvoidprocessPayment(LongorderId){// 支付处理,独立于调用方的事务}@Transactional(propagation=Propagation.REQUIRES_NEW)publicvoidrefundPayment(LongorderId){// 退款处理,即使主事务回滚也提交}}

4. 事务隔离级别

/** * 事务隔离级别解决并发问题: * 脏读:读到未提交的数据 * 不可重复读:同一事务中两次读到不同数据 * 幻读:同一事务中读到新增的数据 */@ServicepublicclassInventoryService{@Transactional(isolation=Isolation.READ_COMMITTED)publicvoidupdateStock(LongproductId,intquantity){// READ_COMMITTED:MySQL 默认级别,解决脏读// REPEATABLE_READ:解决脏读 + 不可重复读// SERIALIZABLE:解决所有并发问题(性能最差)}}
隔离级别脏读不可重复读幻读
READ UNCOMMITTED
READ COMMITTED
REPEATABLE READ
SERIALIZABLE

三、@Async + @Transactional 组合

1. 异步方法中的事务

/** * 异步方法中的 @Transactional 是独立的 * 调用方的异常不会导致异步方法回滚 */@ServicepublicclassAsyncTransactionService{@Async("taskExecutor")@Transactional(rollbackFor=Exception.class)publicvoidasyncWithTransaction(LongorderId){// 这个事务和调用方的事务是独立的orderMapper.updateStatus(orderId,1);}}

2. 注意事项

/** * ❌ 错误:同一类中的方法调用 @Async 不生效 */@ServicepublicclassOrderService{publicvoidcreateOrder(){// 这里调用的 asyncMethod 不会异步执行// 因为 Spring 的代理机制只在外部调用时生效this.asyncMethod();}@AsyncpublicvoidasyncMethod(){// 不会被异步执行!}}/** * ✅ 正确:注入自身代理 */@ServicepublicclassOrderService{@Autowired@LazyprivateOrderServiceself;publicvoidcreateOrder(){self.asyncMethod();// 通过代理调用,异步生效}@AsyncpublicvoidasyncMethod(){// 异步执行}}

四、秒杀系统中的事务应用

1. 秒杀下单事务

@ServicepublicclassSeckillService{@Override@Transactional(rollbackFor=Exception.class)publicOrderdoSeckill(LongproductId,LonguserId){// 1. 校验库存Productproduct=productService.getById(productId);if(product.getStock()<=0){thrownewBusinessException(400,"库存不足");}// 2. 扣减库存(乐观锁)booleansuccess=productService.deductStock(productId);if(!success){thrownewBusinessException(400,"库存不足");}// 3. 创建订单Orderorder=newOrder();order.setUserId(userId);order.setProductId(productId);order.setStatus(0);save(order);returnorder;}}

2. 异步处理超时订单

@ServicepublicclassOrderTimeoutService{@Async("taskExecutor")@Transactional(rollbackFor=Exception.class)publicvoidcancelTimeoutOrder(LongorderId){// 1. 取消订单Orderorder=getById(orderId);if(order==null||order.getStatus()!=0){return;}order.setStatus(2);// 已取消updateById(order);// 2. 归还库存productService.restoreStock(order.getProductId(),order.getQuantity());}}

五、常见问题

1. 事务不回滚

// ❌ 错误:没有指定 rollbackFor@TransactionalpublicvoidcreateOrder(){save(order);thrownewRuntimeException("失败");// RuntimeException 默认回滚thrownewBusinessException("失败");// 自定义异常默认不回滚!}// ✅ 正确:指定 rollbackFor@Transactional(rollbackFor=Exception.class)publicvoidcreateOrder(){save(order);thrownewBusinessException("失败");// 回滚}

2. 异步方法中的异常处理

@Async("taskExecutor")publicvoidprocessAsync(){try{// 业务逻辑}catch(Exceptione){// 异步方法的异常不会被调用方捕获// 必须自己处理log.error("异步处理失败",e);}}

3. 事务与锁的顺序

/** * 获取锁 → 开启事务 → 执行业务 → 提交事务 → 释放锁 * * 不能先释放锁再提交事务,否则其他线程会读到未提交的数据 */publicvoidseckillWithLock(LongproductId,LonguserId){StringlockKey="lock:seckill:"+productId;StringlockValue=UUID.randomUUID().toString();try{// 1. 获取锁booleanlocked=redisLock.lock(lockKey,lockValue,10);if(!locked){thrownewBusinessException(400,"操作太频繁");}// 2. 事务操作seckillService.doSeckill(productId,userId);// 3. 释放锁(在事务提交之后)}finally{redisLock.unlock(lockKey,lockValue);}}

总结

@Async 用于: 耗时操作(发送邮件、短信通知、生成报表) 不依赖主流程结果的副流程(日志记录、数据分析) 实时性要求不高的批量处理 @Transactional 用于: 多表操作(订单+库存、用户+积分) 需要原子性保证的业务(支付、退款、转账)

💡 觉得有用的话,点赞 + 关注【张老师技术栈】吧!每周更新 Java/Python/爬虫 实战干货,不让你白来。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/13 22:54:13

ADK 10.1.26100.2454 部署 Win11PE:7个必备组件包添加与中文环境配置实战

ADK 10.1.26100.2454 构建 Win11PE 全流程&#xff1a;从组件选型到中文环境深度优化在当今企业IT运维和系统部署领域&#xff0c;一个功能完备且高度定制化的Windows预安装环境&#xff08;WinPE&#xff09;已成为系统管理员的标配工具。本文将基于最新发布的ADK 10.1.26100.…

作者头像 李华
网站建设 2026/7/13 22:53:01

SAP MM 自动记账配置详解:OBYC 与 5 种常见业务场景科目确定

SAP MM自动记账配置实战&#xff1a;OBYC事务码与五大业务场景科目映射解析物料管理模块&#xff08;MM&#xff09;作为SAP系统的核心组件&#xff0c;其自动记账功能直接关系到企业财务数据的准确性和业务合规性。本文将深入剖析OBYC事务码的配置逻辑&#xff0c;并通过五大典…

作者头像 李华
网站建设 2026/7/13 22:46:58

VS Code 1.89 + MinGW-w64 GCC 13.2 配置:3步解决C++20标准支持与IntelliSense

VS Code 1.89 MinGW-w64 GCC 13.2&#xff1a;现代C开发环境配置实战 对于追求高效开发的C程序员来说&#xff0c;一个支持最新语言特性的开发环境至关重要。本文将带你从零开始配置一个支持C20标准的开发环境&#xff0c;基于VS Code 1.89和MinGW-w64 GCC 13.2编译器&#xf…

作者头像 李华
网站建设 2026/7/13 22:44:53

工业负载控制:TPD2015FN与PIC18F87J10的智能驱动方案

1. 工业负载控制的核心挑战与方案选型在工业自动化领域&#xff0c;负载控制系统的可靠性直接决定了整个生产线的运行稳定性。我曾在某汽车零部件生产线亲眼目睹过因负载驱动失效导致的整线停产事故——一个价值不到5元的续流二极管故障&#xff0c;造成了超过20万元的生产损失…

作者头像 李华
网站建设 2026/7/13 22:44:53

51单片机--通信/串口

通信协议UART&#xff08;异步&#xff09;、I2C&#xff08;同步&#xff09;、SPI&#xff08;同步&#xff09;、ADC、GPIOUART&#xff1a;Univesal Async Recvie Transmit&#xff0c;通用异步收发器&#xff0c;可以实现与外界设备进行异步 通信 全双工、串行、异步通信方…

作者头像 李华
网站建设 2026/7/13 22:43:44

COSBench 0.4.2.c4 分布式压测配置:3节点Driver部署与性能对比分析

COSBench 0.4.2.c4 分布式压测实战&#xff1a;3节点Driver部署与性能对比分析对象存储性能测试是验证系统可靠性和扩展性的关键环节。作为一款开源的分布式压测工具&#xff0c;COSBench 0.4.2.c4版本在测试云存储服务时展现出独特的优势。本文将深入探讨多节点Driver部署方案…

作者头像 李华