为什么Spring没有为关系型数据库提供反应式(非阻塞)客户端?

18

我曾使用Vert.x工具包创建支持关系型数据库,如MySQL和Postgres的响应式应用程序。我知道Spring提供了一些NoSQL数据库(如Cassandra和Mongo)的响应式支持,但他们是否愿意为关系型数据库提供相同的支持呢?


Spring WebFlux和rxjava2-jdbc,作者为Robert B Roeser https://link.medium.com/6ONWHPEsKR - uneq95
https://dev59.com/llgQ5IYBdhLWcg3wvGYY - uneq95
https://www.baeldung.com/rxjava-jdbc - uneq95
https://github.com/davidmoten/rxjava2-jdbc - uneq95
1
异步JDBC仍在开发中:https://blogs.oracle.com/java/jdbc-next:-a-new-asynchronous-api-for-connecting-to-a-database - duffymo
2个回答

41

Spring Framework的理念是什么?

Spring Framework是一个旨在提高开发人员生产力的库,Spring Data、Spring Security和Spring Cloud等Spring组合项目也是如此。

这些项目基于已经通过JSR或JEP标准化或被证明有用且广泛使用的库的现有API构建。Spring团队不会为数据库或其他集成构建驱动程序,这取决于数据库/驱动程序供应商。

WebFlux与Vert.x的比较

Spring WebFlux是典型Spring模块的一个很好的例子。它在现有的非阻塞服务器(通过netty、Undertow和Jetty的Project Reactor)之上构建。WebFlux提供了一个运行时容器,用于非阻塞反应式应用程序,利用Spring组件来协助开发和运行这些应用程序。

Vert.x是一个提供自己低级实现的综合环境的优秀示例。Vert.x进行了大量优化,这样的生态系统需要进行优化的集成。Vert.x为各种数据库提供了自己的实现,并提供在Vert.x上下文中良好工作的API,但这些API不是JDBC。

关系数据库API

正如M-Razavi所提到的,Java使用JDBC与关系数据库集成,而JDBC具有阻塞性——无法合理地减轻JDBC的阻塞性。将JDBC调用卸载到Executor(通常是Thread池)中的效用受到限制,因为池最终会饱和请求)。简而言之,没有可用于提供反应式关系数据库集成的API。

那么有哪些选择呢?

M-Razavi已经提到了ADBA,这是Oracle推出的一个使用futures在Java中提供异步数据库访问的标准API。ADBA中的所有内容仍在不断改进中,ADBA团队很乐意得到反馈。一群Postgres开发人员正在开发Postgres ADBA driver,可用于首次实验。

然而,ADBA是未来的目标,我认为我们不会在Java 12中看到ADBA的发布。

还有一些独立的驱动程序,比如Reactiverse的reactive-pg-client。这些驱动程序带有特定于供应商的API,并不适合在Spring中进行更广泛的集成。我们需要提供额外的层以公开通用API,并且新的驱动程序不能只是插入应用程序,使其直接运行。拥有标准API允许可插性,因此拥有标准API具有巨大价值。

R2DBC来拯救局面?

缺乏标准API和驱动程序不可用,Pivotal的一个团队开始研究一种反应式关系API,这将是反应式编程目的的理想选择。他们提出了R2DBC,它代表反应式关系数据库连接。截至目前,R2DBC是一个孵化器项目,旨在评估可行性并开始讨论是否有驱动程序供应商有兴趣支持反应式/非阻塞/异步驱动程序。
目前,有三个驱动程序实现:
- PostgreSQL - H2 - Microsoft SQL Server R2DBC带有API规范(r2dbc-spi)和客户端(r2dbc-client),使SPI可用于应用程序。我们开始探索Spring Data R2DBC集成,通过数据库客户端提供反应式API,并支持反应式存储库。
R2DBC及其生态系统仍然年轻,需要进行实验和反馈,以收集用例并查看反应式关系数据库集成是否有意义。

目前,你可以通过Spring Data使用R2DBC,以下代码片段展示了DatabaseClient的用法:

PostgresqlConnectionFactory connectionFactory = new PostgresqlConnectionFactory(…);

DatabaseClient databaseClient = DatabaseClient.create(connectionFactory);

Mono<Integer> count = databaseClient.execute()
                .sql("INSERT INTO legoset (id, name, manual) VALUES($1, $2, $3)")
                .bind("$1", 42055)
                .bind("$2", "Description")
                .bindNull("$3", Integer.class)
                .fetch()
                .rowsUpdated();

Flux<Map<String, Object>> rows = databaseClient.execute()
                .sql("SELECT id, name, manual FROM legoset")
                .fetch()
                .all();

你能否更新你的回答,加入R2DBC MySQL支持?谢谢。 - nicolasl
同时,ADBA项目已经停止。 - Imaskar
@mp911de 为什么R2DBC不能与Hibernate Reactive集成? - jimbob542

10

Spring WebFlux 是创建非阻塞 REST 应用程序的好方法。当开始使用 WebFlux 时,遇到的一个问题是 JDBC,因为 JDBC 是阻塞的。新型数据库(如 Cassandra 或 Couchbase)具有非阻塞驱动程序。在 Couchbase 的情况下,它的驱动程序使用 RXJava。目前正在努力创建异步数据库驱动程序,以及 Oracle 创建 ADBA 的努力。不幸的是,这些都还处于早期阶段,如果要在 JVM 上访问 SQL 数据库,则必须使用阻塞驱动程序。
实际上,Spring 不负责为关系型数据库提供非阻塞驱动程序。


2
我不知道为什么这个被踩了,但我也读到过JDBC本质上是阻塞的。 - uneq95
你说得没错,但是我在想,就像Vert.x这样的其他工具也为关系型数据库提供了异步客户端。 - Mohamed Elsayed
1
大多数情况下,这些工具只是在阻塞的数据库客户端上涂口红(在与连接池大小相同的托管线程池中执行它),然后称其为响应式。参见例如 https://dev59.com/Pqvka4cB1Zd3GeqPuYWk - Simon Baslé
嗯...看起来是真的,我之前不知道。 - Mohamed Elsayed
我已经阅读过,使用Reactor与阻塞式数据库(例如JDBC)没有任何用处,因为数据库会在检索数据时使线程等待。你有什么想法? - Christopher Barrett

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接