В чем идея Spring Framework?
Spring Framework - это библиотека для повышения производительности труда разработчиков, как и портфельные проекты Spring, такие как Spring Data, Spring Security, Spring Cloud.
Эти проекты основаны на существующих API, которые либо стандартизированы с помощью JSR или JEP, либо на основе библиотек, которые оказались полезными и широко используемыми. Команда Spring не создает драйверы для баз данных или других интеграций, это зависит от поставщиков баз данных / драйверов.
WebFlux по сравнению с Vert.x
Spring WebFlux является хорошим примером для типичного модуля Spring. Он построен поверх существующих неблокирующих серверов (Project Reactor через netty, Undertow и Jetty). WebFlux предоставляет контейнер времени выполнения для неблокирующих реактивных приложений, использующих компоненты Spring для помощи в разработке и запуске таких приложений.
Vert.x является отличным примером интегрированной среды, которая предоставляет свои собственные низкоуровневые реализации. Vert.x сильно оптимизирован, и такая экосистема требует оптимизированных интеграций. Vert.x предложил собственные реализации для различных баз данных и предоставляет API, которые хорошо работают в контексте Vert.x, но эти API не являются JDBC.
API реляционных баз данных
Как уже упоминалось M-Razavi , Java использует JDBC для интеграции с реляционными базами данных, а JDBC имеет блокирующую природу - нет ничего разумного в том, чтобы смягчить блокирующую природу JDBC. Разгрузка вызовов JDBC в Executor
(обычно Thread
пул) ограничена в его полезности, поскольку пул в конечном итоге насыщается запросами). TL; DR, нет API, поверх которого мы могли бы обеспечить реактивную интеграцию реляционной базы данных.
Так, каковы варианты?
M-Razavi уже упоминалось ADBA , которая является инициативой Oracle по предоставлению стандартизированного API для асинхронного доступа к базе данных в Java с использованием фьючерсов. Все в ADBA все еще находится в стадии разработки, и команда ADBA рада получить обратную связь. Группа сотрудников Postgres работает над драйвером Postgres ADBA , который можно использовать для первых экспериментов.
Однако ADBA - это будущая цель, и я ожидаю, что мы не увидим ADBA, выпущенную с Java 12.
Существует пара независимых драйверов, таких как Reactiverse's реактивный-pg-клиент . Эти драйверы поставляются с API-интерфейсом конкретного производителя и не очень подходят для более широкой интеграции в Spring. Нам потребуется предоставить дополнительные уровни для предоставления общего API, и новые драйверы нельзя просто подключить к вашему приложению, чтобы оно работало «из коробки» ™. Наличие стандартного API обеспечивает возможность подключения, поэтому наличие стандартного API имеет огромное значение.
R2DBC на помощь?
Из-за отсутствия стандартного API и отсутствия драйверов команда Pivotal начала исследовать реактивный реляционный API, который идеально подходил бы для целей реактивного программирования. Они придумали R2DBC , что означает Reactive Relational Database Connectivity. На данный момент R2DBC является проектом инкубатора для оценки выполнимости и начала обсуждения того, заинтересованы ли производители драйверов вообще в поддержке реактивных / неблокирующих / асинхронных драйверов.
На данный момент существует три реализации драйвера:
R2DBC поставляется со спецификацией API (r2dbc-spi
) и клиентом (r2dbc-client
), что делает SPI пригодным для использования в приложениях. Мы начали исследовать интеграцию Spring Data R2DBC , которая предоставляет реактивные API через клиент базы данных и поддержку реактивных репозиториев.
R2DBC и его экосистема еще молоды и требуют экспериментов и обратной связи для сбора вариантов использования и определения целесообразности реактивной интеграции реляционных баз данных.
Прямо сейчас вы можете использовать R2DBC через Spring Data, и следующий фрагмент показывает 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();