Spring 框架背后的想法是什么?
Spring Framework 是一个提高开发人员生产力的库,Spring Data、Spring Security、Spring Cloud 等 Spring 的组合项目也是如此。
这些项目构建在现有 API 之上,这些 API 要么通过 JSR 或 JEP 进行标准化,要么构建在已被证明有用且广泛使用的库之上。 Spring 团队不为数据库或其他集成构建驱动程序,这取决于数据库/驱动程序供应商。
WebFlux 与 Vert.x 相比
Spring WebFlux 是典型 Spring 模块的一个很好的例子。它构建在现有的非阻塞服务器之上(Project Reactor via netty、Undertow 和 Jetty)。 WebFlux 为非阻塞、反应式应用程序提供了一个运行时容器,利用 Spring 组件来协助开发和运行此类应用程序。
Vert.x 是集成环境的一个很好的例子,它提供了自己的低级实现。 Vert.x 进行了大量优化,这样的生态系统需要优化集成。 Vert.x 为各种数据库提出了自己的实现,并提供了在 Vert.x 上下文中运行良好的 API,但这些 API 不是 JDBC。
关系数据库 API
As M-Razavi https://stackoverflow.com/users/601288/m-razavi前面已经提到,Java 使用 JDBC 与关系数据库集成,而 JDBC 具有阻塞性质——没有任何明智的措施可以减轻 JDBC 的阻塞性质。将 JDBC 调用卸载到Executor
(通常Thread
池)的实用性受到限制,因为池最终会因请求而饱和)。 TL;DR,没有可用的 API 可以让我们提供反应式关系数据库集成。
那么有哪些选择呢?
M-Razavi https://stackoverflow.com/users/601288/m-razavi已经提到过ADBA https://blogs.oracle.com/java/jdbc-next:-a-new-asynchronous-api-for-connecting-to-a-database这是 Oracle 的一项举措,旨在为使用 future 的 Java 异步数据库访问提供标准化 API。 ADBA 的所有工作仍在进行中,ADBA 背后的团队很高兴收到反馈。一群 Postgres 人员正在开发一个Postgres ADBA 驱动程序 https://github.com/pgjdbc/pgadba可用于第一次实验。
然而,ADBA 是一个未来的目标,我预计我们不会看到 ADBA 与 Java 12 一起发布。
有几个独立的驱动程序,例如Reactiveverse 的reactive-pg-client https://github.com/reactiverse/reactive-pg-client。这些驱动程序带有特定于供应商的 API,并不真正适合在 Spring 中进行更广泛的集成。我们需要提供额外的层来公开通用 API,并且新的驱动程序不能只是插入到您的应用程序中,以便它可以开箱即用™。拥有标准 API 可以实现可插拔性,因此拥有标准 API 具有巨大的价值。
R2DBC 来救援?
由于缺乏标准 API 和驱动程序,团队Pivotal https://pivotal.io开始研究一种非常适合反应式编程目的的反应式关系 API。他们想出了R2DBC http://r2dbc.io它代表反应式关系数据库连接。截至目前,R2DBC 是一个孵化器项目,用于评估可行性并开始讨论驱动程序供应商是否有兴趣支持反应式/非阻塞/异步驱动程序。
到目前为止,共有三种驱动程序实现:
- PostgreSQL https://github.com/r2dbc/r2dbc-postgresql
- H2 https://github.com/r2dbc/r2dbc-h2
- 微软SQL服务器 https://github.com/r2dbc/r2dbc-mssql
R2DBC 附带 API 规范(r2dbc-spi
)和一个客户(r2dbc-client
)使 SPI 可用于应用程序。我们开始探索Spring Data R2DBC https://github.com/spring-projects/spring-data-r2dbc通过数据库客户端和支持反应式存储库提供反应式 API 的集成。
R2DBC 及其生态系统还很年轻,需要进行实验和反馈来收集用例并看看反应式关系数据库集成是否有意义。
现在,您可以通过 Spring Data 使用 R2DBC,以下代码片段显示DatabaseClient
usage:
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();