阻塞 Spring 数据和反应性 Spring 数据之间的区别?

Difference between blocking Spring Data and reactive Spring Data?

如果我们可以将标准阻塞查询结果包装在反应流中,为什么我们需要非阻塞数据库连接器? Mongo、Redis 等非阻塞连接器实际上是从数据源流式传输数据,还是以阻塞方式获取数据,然后从内存中流式传输?查询示例 Mongo:

public interface ItemReactiveRepository extends ReactiveMongoRepository<Item,String> {

    //
}

...
Flux<Item> itemsFlux = itemReactiveRepository.findAll();

public interface ItemRepository extends MongoRepository<User, String> {
    // 
}
...
List<Item> itemsList = itemRepository.findAll(); 
Flux<Items> itemsFlux = Flux.fromIterable(itemsList );

如果有人能花时间解释一下,或者投稿link我将不胜感激

简短的回答是可扩展性

阻塞世界(JDBC、JPA 等)中,如果您想同时执行许多数据库查询,那么您需要尽可能多的线程您要执行的许多并发数据库查询。这工作正常,直到某一点。但是,线程不是免费的:它们需要内存,并且上下文切换会花费 CPU 时间。所以你的并发越多,你的系统就越挣扎。

非阻塞 IO(R2DBC、Reactive Mongo Driver 等)和 reactive 来了,它可以让你摆脱这种 thread-per-connection 模型并允许您通过使用固定的少量线程(通常等于 CPU 核心数)实现相同的并发性。该模型提供了更高的可扩展性。

如果您只是将阻塞代码包装到一个反应流中,您就不会摆脱每个连接一个线程的模型,您只会隐藏问题并最终会遇到同样的可伸缩性问题。

响应式代码不仅仅是 "using different objects" 的情况。这是一种根本不同的编写代码的方式,以确保线程永远不会阻塞(或等待)其他事情发生。它要么正忙着做一些处理,要么准备好等待。这些对象只是以那种风格编写代码的副作用。

理论上,我们可以使用现有的 Java 对象并仅使用 "callbacks" 来编写该代码。然而,虽然这种方法对于在 UI 上单击的按钮工作正常,但如果您尝试扩展该方法,您很快就会陷入 "callback hell"。这就是我们拥有提供 FluxMono 等对象的框架的原因,使我们能够以更明智、更强大的方式管理非阻塞代码。

这些对象还提供实用方法来获取 "standard" 对象并包装它们(例如 fromIterable()just()。)这些在某些情况下很有用,但可能会被滥用 -你的第二个例子就是这样;一些人称之为 "imposter" 反应式代码的案例。它根本不是 "reactive" 或非阻塞,它只是将阻塞方法调用包装在反应对象中,使它们看起来是反应性的。这很糟糕,因为这意味着人们使用你的方法,假设他们是反应性的,因为他们 看起来 反应性,实际上最终会在非阻塞线程上调用阻塞代码。这要么会导致整个实施崩溃,要么会严重减慢速度,然后可能意味着需要引入诸如 Blockhound 之类的工具来追踪正在发生的事情。

简而言之,不可能采用阻塞代码并使其成为非阻塞代码 - 所以如果您认为自己以某种方式做到了,那您就错了。它必须从头开始编写(不幸的是,这就是为什么 Java 上的完整反应式堆栈需要这么长时间才能变得可行。)然而,另一种方式是微不足道的 - 你可以阻止你的任何反应式调用想要。