如何解决用于简单 RESTful 调用的反应式 R2DBC
由于 R2DBC 是响应式且非阻塞的,我想了解在简单的 RESTful CRUD 服务中使用 R2DBC 的好处
假设一个 spring boot 应用程序使用下面的存储库公开一个 RESTful 服务
public interface CustomerRepository extends ReactiveCrudRepository<Customer,Long> {
@Query("SELECT * FROM customer WHERE last_name = :lastname")
Flux<Customer> findByLastName(String lastName);
}
这个存储库是从服务中调用的,结果需要在服务中进行转换,然后才能返回控制器。
Flux<Customer> customers = repository.findAll();
为了访问完整的客户列表,我需要在 Flux 上调用 blockLast()
,这使其阻塞并违背了使用反应式组件的目的
这是否意味着在这个简单示例中使用 R2DBC 没有任何好处?我错过了什么吗?
flux 能否仅用于异步订阅,其中 Flux 集合的处理发生在不同的线程中?
解决方法
为了访问完整的客户列表,我需要在 Flux 上调用 blockLast() 这使它阻塞并破坏了使用反应组件的目的
如果您想实际获得对 blockLast()
的引用,您只需要调用 List<Customer>
- 但正如您所说,如果您这样做,您将失去所有反应优势。 (您真正应该考虑阻止恕我直言的唯一时间是,如果您要迁移到反应式系统,并将反应式库放置到位,但尚未准备好使整个系统变为反应式。)
如果您只想一次访问完整的客户列表,您可以明智地调用 collectList()
以获取 Mono<List<Customer>
。这样你就可以留在反应式上下文中,但在任何反应式运算符中,你都可以使用整个列表。
这里唯一需要注意的是内存占用——如果你只是按原样处理一个 Flux<Customer>
,那么你永远不需要在内存中存储一组它们,所以它真的不重要有很多(甚至可以是无限的。)如果您先将其收集到列表中,那么所有这些客户都必须同时存储在内存中。
这是否是一个问题取决于您的用例。如果您谈论的是 10 个左右的客户,那完全没问题。如果您谈论的是数十亿美元,那么这很可能不是一个明智的解决方案。
,- 由于该方法返回一个
Flux
,所以它返回一个可以在未来某个时间完成的承诺。 - 调用此方法的线程不应阻塞 - 这就是响应式的全部意义所在。如果您使用
.blockLast()
,您将使调用线程阻塞。正如迈克尔在此回答中所说,只有在将反应式和非反应式代码集成在一起时才应该这样做。 - 这是一张解释异步方式的图表。计算是工作(反应式、
CompletableFuture
等)。希望这能消除您的疑虑;
如您在图中所见,如果您执行 .blockLast()
,您将失去真正的非阻塞。理想情况下,调用线程应该立即释放,以便它可以做其他工作。
- 一个正确编写的反应式应用程序将是一个单链,订阅发生在最上层。整个应用程序应该是一个异步管道。您应该使用
BlockHound
之类的应用程序来检查您的线程是否在任何地方阻塞。
“flux 能否仅用于异步订阅,其中 Flux 集合的处理发生在不同的线程中?” - Flux 只不过是一个承诺,表示它可以在未来的某个时间完成。如图所示,回调将在异步线程上执行。计算完成。您可以使用 .publishOn()
切换此线程。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。