

Spring中使用@Async与@Transactional协调异步与事务处理
source link: https://www.jdon.com/72575.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Spring中使用@Async与@Transactional协调异步与事务处理
本文旨在阐明 Spring@Transactional和@Async注释的协同使用,提供对它们的集体应用程序的见解,以优化 Java 应用程序的性能。
什么是 Spring 中的事务管理
事务管理在任何企业应用程序中对于确保数据一致性和完整性都至关重要。在Spring中,这是通过@Transactional注解来实现的,注解抽象了底层的事务管理机制,使开发人员更容易以声明方式控制事务边界。
@Transactional 注解
Spring中的注解@Transactional可以应用于类和方法级别。它声明类的一个方法或所有方法应该在事务上下文中执行。
Spring@Transactional支持各种属性,例如propagation、isolation、timeout和readOnly,允许微调事务管理。
- 传播Propagation:定义事务如何相互关联;常见选项包括REQUIRED、REQUIRES_NEW和SUPPORTS
- 隔离性Isolation:确定一项事务所做的更改如何对其他事务可见;选项包括READ_UNCOMMITTED、READ_COMMITTED、REPEATABLE_READ和SERIALIZABLE。
- 超时Timeout:指定事务必须完成的时间范围
- ReadOnly:表示事务是否只读,优化某些数据库操作
Spring中的异步编程是什么
Spring 中的异步操作通过 @Async 注解进行管理,使方法调用在后台线程池中运行,从而不会阻塞调用线程。这对于耗时或独立于主执行流的操作尤其有利。
@Async 注解
只要 Spring 任务执行器配置正确,用 @Async 标记一个方法就能使其异步执行。此注解可用于返回 void、Future 或 CompletableFuture 对象的方法,允许调用者跟踪操作的进度和结果。
将 @Transactional 与 @Async 结合起来
将事务管理与异步操作相结合会带来独特的挑战和难度,这主要是因为事务与线程的上下文相关联,而 @Async 会导致方法执行切换到不同的线程。
异步与事务结合的问题
挑战和考虑因素
- 事务上下文传播:从 @Transactional 上下文中调用 @Async 方法时,事务上下文不会自动传播到异步方法执行线程。
- 最佳实践:要在异步方法中管理事务,关键是要确保负责事务管理的方法与标有 @Async 的方法不是同一个。相反,异步方法应调用另一个 @Transactional 方法,以确保正确建立事务上下文。
@Service |
在本例中,processInvoices 是一个异步方法,它调用 updateInvoiceStatus(一个事务方法)。这种分离可确保在异步执行上下文中进行适当的事务管理。
@Service |
在这里,generateReportAsync 异步执行并返回 CompletableFuture,而 generateReport 则处理报告生成的事务性问题。
关于事务传播的讨论
Spring 中的事务传播行为定义了事务之间的关系,尤其是在一个事务方法调用另一个事务方法的情况下。选择正确的传播行为对于实现所需的事务语义至关重要。
- REQUIRED (默认):这是默认的传播行为。如果存在现有事务,方法将在该事务中运行。如果没有现有事务,Spring 将创建一个新事务。
- REQUIRES_NEW:此行为总是启动一个新事务。如果有一个现有事务,它将被暂停,直到新事务完成。当你需要确保方法在一个新的、独立的事务中执行时,这种方式非常有用。
- SUPPORTS:使用此行为时,如果存在事务,方法将在现有事务中执行。但是,如果没有现有事务,方法将以非事务方式运行。
- NOT_SUPPORTED(不支持):此行为将以非事务方式执行方法。如果存在事务,该事务将被暂停,直到方法完成。
- MANDATORY(必须):此行为要求有一个现有事务。如果没有现有事务,Spring 将抛出异常。
- NEVER:该方法绝不应在事务中运行。如果存在事务,Spring 将抛出异常。
- NESTED:如果存在现有事务,该行为将启动嵌套事务。嵌套事务允许部分提交和回滚,某些事务管理器(但并非所有事务管理器)都支持嵌套事务。
异步操作的传播行为
将 @Transactional 与 @Async 结合使用时,理解传播行为的含义变得更加重要。由于异步方法在单独的线程中运行,某些传播行为可能会因为新线程中没有事务上下文而无法按预期运行。
- REQUIRED 和 REQUIRES_NEW:这是最常用、最直接的行为。不过,当与 @Async 一起使用时,REQUIRES_NEW 行为通常更可预测,因为它能确保异步方法始终启动一个新事务,避免与调用方法的事务发生意外交互。
- SUPPORTS、NOT_SUPPORTED、MANDATORY、NEVER:当与 @Async 一起使用时,这些行为可能会导致意想不到的结果,因为调用线程的事务上下文不会传播到异步方法的线程。在异步处理中使用这些行为时,需要仔细考虑和测试。
- NESTED:鉴于嵌套事务的复杂性和 @Async 方法的独立线程上下文,一般不建议在异步操作中使用嵌套事务。它可能导致复杂的事务管理情况,难以调试和维护。
异步操作的传播
为了说明不同传播行为与异步操作之间的交互,让我们来考虑一个异步服务方法调用具有不同传播行为的事务方法的示例。
@Service |
在本例中,processOrdersAsync 是一个异步方法,用于处理订单列表。它调用每个订单上的 updateOrderStatus,并用 @Transactional(propagation = Propagation.REQUIRES_NEW)标记。这确保了每个订单状态更新都发生在一个新的、独立的事务中,将每个更新操作与其他操作和原始异步流程隔离开来。
示例@Transactional(REQUIRES_NEW) 与@Async
@Service |
在这里,updateUserAsync 是一个异步方法,它调用 updateUser,这是一个注释了 @Transactional 和 REQUIRES_NEW 传播行为的方法。这种配置可确保每次用户更新操作都在一个新事务中进行,并与任何现有事务隔离。这在更新操作必须不受其他事务结果影响的情况下特别有用。
在类级别上将 @Async 与 @Transactional 结合起来
@Service |
在这种情况下,OrderService 类被注释为 @Transactional,默认情况下对其所有方法应用事务管理。带有 @Async 标记的 processOrderAsync 方法通过调用 processOrder 异步执行订单处理。类级 @Transactional 注解确保订单业务处理逻辑能在事务上下文中执行,从而为相关数据库操作提供一致性和完整性。
@Async 方法调用多个 @Transactional 方法
@Service |
此示例中的异步方法 generateReportAsync 通过调用两个独立的事务方法:prepareData 和 saveReport 来协调报告生成过程。
- prepareData 方法封装在默认事务上下文中,
- 而 saveReport 被明确配置为始终在新事务中执行。
这种设置非常适合报告保存操作saveReport 需要在事务上独立于数据准备阶段prepareData 的情况,可确保报告的保存saveReport不受前面操作成功或失败的影响。
上述每个示例都展示了如何通过 @Transactional 和 @Async 的不同组合,在异步处理上下文中实现特定的事务行为,从而为 Spring 开发人员提供了根据应用程序要求定制事务管理策略的灵活性。
结论
在 Spring 应用程序中,了解并谨慎选择适当的事务传播行为至关重要,尤其是在将事务操作与异步处理相结合时。通过考虑每种传播行为的具体要求和影响,开发人员可以在其 Spring 应用程序中设计出更稳健、高效和可靠的事务管理策略。有了这些扩展知识,就能更自信、更精确地处理复杂的事务场景,最终实现更高质量的软件解决方案。
Recommend
-
44
-
42
公众号[ JavaQ ]原创,专注分享Java基础原理分析、实战技术、微服务架构、分布式系统构建,诚邀点赞关注! 面试官 :有如下代码场景,A类的a1方法没有标注@Transactional注解,a2方法标...
-
16
前言 本专题大纲: 我重新整理了大纲,思考了很久,决定单独将MySQL的事务实现原理跟Spring中的事务示例分为两篇文章,因为...
-
8
.NET Web应用中为什么要使用async/await异步编程?前言1.什么是async/aw...
-
8
[Spring声明式事务使用的那些坑] 最全的@Transactional注解的避坑指南哈喽小伙伴们,俺是啤酒熊,今天想来和大家聊聊Spring中涉及数据库事务的一些坑。Spring
-
6
我的需求是创建一个新线程来执行一些操作,因为如果用同一个线程就会导致资源一直被占据,影响响应效率。异步的概念我的理解:异步即为在多辆车在多条路上行驶,同步即为多辆车在一条路上行驶。举个栗子:同...
-
12
-
5
HTML5让我兴奋的一个最大的原因是,它里面实现的新功能和新特征都是我们长久以来一直期待的。比如,我以前一直在使用placeholders,但以前必须要用JavaScript实现。而HTML5里给JavaScript标...
-
4
转载请注明出处: 1.Promise 的 then 方法使用 then 方法是 Promise 中 处理的是异步调用,异步调用是非阻塞式的,在调用的时候并不知道它什么时候结束,也就不会等到他返回一个有效数据之后再进行下一步处理; 想了解 Promise...
-
6
Spring异步Async和事务Transactional注解 Spring开发...
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK