Возможно ли использовать асинхронный вызов jdbc?

Интересно, есть ли способ сделать асинхронные вызовы в базе данных?

Например, представьте, что у меня большой запрос, который занимает очень много времени для обработки, я хочу отправить запрос и получить уведомление, когда запрос вернет значение (передав Listener/callback или что-то еще), Я не хочу блокировать ожидание ответа базы данных.

Я не считаю, что использование пула потоков является решением, потому что оно не масштабируется, в случае тяжелых параллельных запросов это порождает очень большое количество потоков.

Мы сталкиваемся с такой проблемой с сетевыми серверами, и мы нашли решения, используя системный вызов select/poll/epoll, чтобы избежать использования одного потока для каждого соединения. Мне просто интересно, как иметь подобную функцию с запросом базы данных?

Примечание: Я знаю, что использование FixedThreadPool может быть хорошей практикой, но я удивлен, что никто не разработал систему, которая действительно асинхронна (без использования дополнительного потока).

** Обновление **
Из-за отсутствия реальных практических решений я решил сам создать библиотеку (часть finagle): finagle-mysql. Он в основном декодирует/декодирует запрос/ответ mysql и использует Finagle/Netty под капотом. Он очень хорошо масштабируется даже при большом количестве подключений.

Ответ 1

Я не понимаю, как какой-либо из предложенных подходов, которые обертывают вызовы JDBC в Актеры, исполнители или что-то еще, может помочь здесь - может кто-то уточнить.

Несомненно, основная проблема заключается в том, что блок операций JDBC в сокете IO. Когда он делает это, он блокирует поток, который работает на конце истории. Какую бы фреймворческую оболочку вы не решили использовать, чтобы в конечном итоге один поток был занят/заблокирован на один параллельный запрос.

Если базовые драйверы базы данных (MySql?) предлагают средство для перехвата создания сокета (см. SocketFactory), то я предполагаю, что можно было бы создать слой базы данных, основанный на async-событий, поверх api JDBC, но мы бы чтобы инкапсулировать весь JDBC за фасад, управляемый событиями, и этот фасад не будет похож на JDBC (после того, как он будет управляться событиями). Обработка базы данных будет происходить как асинхронный для другого потока для вызывающего, и вам нужно будет разработать, как создать диспетчер транзакций, который не полагается на сходство потоков.

Что-то вроде подхода, о котором я упоминал, позволит даже одному фоновому потоку обрабатывать нагрузку параллельных JDBC-exec. На практике вы, вероятно, запускаете пул потоков, чтобы использовать несколько ядер.

(Конечно, я не комментирую логику исходного вопроса только ответы, которые подразумевают, что concurrency в сценарии с блокирующим сокером IO возможен без пользователя шаблона селектора - проще просто выработать свой типичный JDBC concurrency и добавьте пул соединений нужного размера).


Похоже, что MySql, вероятно, делает что-то по строкам, которые я предлагаю --- http://code.google.com/p/async-mysql-connector/wiki/UsageExample

Ответ 2

Невозможно выполнить асинхронный вызов базы данных через JDBC, но вы можете сделать асинхронные вызовы в JDBC с помощью Актеров (например, актер совершает вызовы в БД через JDBC и отправляет сообщения в третьи стороны, когда вызовы закончены), или, если вам нравится CPS, конвейерные фьючерсы (promises) (хорошая реализация Scalaz Promises)

Я не считаю, что использование пула потоков является решением, потому что оно не масштабируется, в случае тяжелых параллельных запросов это порождает очень большое количество потоков.

Scala субъекты по умолчанию основаны на событиях (не на основе потоков) - планирование продолжения позволяет создавать миллионы участников на стандартной установке JVM.

Если вы ориентируетесь на Java, Akka Framework является реализацией модели Actor, которая имеет хороший API как для Java, так и для Scala.


Кроме того, синхронный характер JDBC имеет для меня прекрасный смысл. Стоимость сеанса базы данных намного выше, чем затраты на поток Java, который блокируется (как на переднем, так и на заднем плане) и ожидает ответа. Если ваши запросы выполняются так долго, что возможности службы-исполнителя (или обертывания фреймворков Actor/fork-join/prom

Ответ 3

Возможно, вы могли бы использовать систему асинхронных сообщений JMS, которая очень хорошо масштабируется, ИМХО:

  • Отправить сообщение в очередь, где подписчики будут принимать это сообщение и запустить SQL-процесс. Ваш основной процесс продолжит выполнение и принятие или отправку новых запросов.

  • Когда процесс SQL заканчивается, вы можете запустить обратный путь: отправить сообщение ResponseQueue с результатом процесса, а слушатель на стороне клиента принять его и выполнить код обратного вызова.

Ответ 4

В JDBC нет прямой поддержки, но у вас есть несколько параметров, таких как MDB, Executors из Java 5.

"Я не считаю, что использование пула потоков является решением, потому что оно не масштабируется, в случае тяжелых одновременных запросов это порождает очень большое количество потоков".

Мне любопытно, почему ограниченный пул потоков не будет масштабироваться? Это пул, а не поток на запрос, чтобы порождать поток за каждый запрос. Я использую это довольно часто в режиме большой загрузки webapp, и мы пока не видели никаких проблем.

Ответ 5

Похоже, что новый асинхронный jdbc API "JDBC следующий" находится в работе.

См. презентация здесь

Вы можете загрузить API из здесь

Ответ 6

Как уже упоминалось в других ответах, JDBC API не является асинхронным по своей природе.
Однако, если вы можете жить с подмножеством операций и другим API, есть решения. Одним из примеров является https://github.com/jasync-sql/jasync-sql, который работает для MySQL и PostgreSQL.

Ответ 7

Проект Ajdbc, кажется, отвечает на эту проблему http://code.google.com/p/adbcj/

В настоящее время существует 2 экспериментальных асинхронных драйвера для mysql и postgresql.

Ответ 8

Старый вопрос, но еще немного информации. Невозможно, чтобы JDBC выдавал асинхронные запросы самой базе данных, если поставщик не предоставляет расширение JDBC и оболочку для обработки JDBC. Тем не менее, можно обернуть сам JDBC очереди обработки и реализовать логику, которая может обрабатывать очередь на одном или нескольких отдельных соединениях. Одним из преимуществ этого для некоторых типов вызовов является то, что логика, если она находится при достаточно большой нагрузке, может преобразовывать вызовы в пакеты JDBC для обработки, что значительно ускорит логику. Это наиболее полезно для вызовов, где данные вставляются, и фактический результат нужно регистрировать только в случае возникновения ошибки. Хорошим примером этого является то, что для регистрации активности пользователя выполняются вставки. Приложение не заботится, будет ли вызов завершен немедленно или через несколько секунд.

В качестве побочного примечания один продукт на рынке обеспечивает политический подход к разрешению асинхронных вызовов, подобных тем, которые я описал, асинхронно (http://www.heimdalldata.com/). Отказ от ответственности: Я являюсь соучредителем этой компании. Это позволяет использовать регулярные выражения для запросов преобразования данных, таких как вставка/обновление/удаление для любого источника данных JDBC, и будет автоматически их совместно обрабатывать для обработки. При использовании с MySQL и параметром rewriteBatchedStatements (MySQL и JDBC с rewriteBatchedStatements = true) это может значительно снизить общую нагрузку на базу данных.

Ответ 9

У меня есть три варианта:

  • Используйте параллельную очередь для распространения сообщений через небольшое и фиксированное количество потоков. Так что если у вас 1000 соединений, у вас будет 4 потока, а не 1000 потоков.
  • Доступ к базе данных на другом node (т.е. другой процесс или машина) и клиент базы данных асинхронные сетевые вызовы, чтобы node.
  • Реализовать истинную распределенную систему через асинхронные сообщения. Для этого вам понадобится очередь сообщений, такая как CoralMQ или Tibco.

Diclaimer: Я один из разработчиков CoralMQ.

Ответ 10

Java 5.0-исполнители могут пригодиться.

У вас может быть фиксированное количество потоков для обработки длительных операций. Вместо Runnable вы можете использовать Callable, которые возвращают результат. Результат заключен в объект Future<ReturnType>, поэтому вы можете получить его, когда он вернется.

Ответ 11

Просто сумасшедшая идея: вы можете использовать шаблон Iteratee над JBDC resultSet, завернутый в некое Future/Promise

Хаммерсмит делает это для MongoDB.

Ответ 13

Я просто думаю об этом здесь. Почему у вас не было пула соединений с базой данных, каждый из которых имеет поток. Каждый поток имеет доступ к очереди. Когда вы хотите выполнить запрос, который занимает много времени, вы можете поставить очередь, а затем один из потоков подберет его и обработает. У вас никогда не будет слишком много потоков, потому что количество ваших потоков ограничено.

Изменить: Или еще лучше, просто несколько потоков. Когда поток видит что-то в очереди, он запрашивает соединение из пула и обрабатывает его.

Ответ 14

Библиотека commons-dbutils поддерживает AsyncQueryRunner, который вы предоставляете ExecutorService, и возвращает Future. Стоит проверить, как это просто использовать и гарантировать, что вы не будете утечки ресурсов.

Ответ 15

Если вас интересуют API-интерфейсы для асинхронных баз данных для Java, вы должны знать, что появилась новая инициатива по разработке набора стандартных API-интерфейсов, основанных на CompletableFuture и lambdas. Существует также реализация этих API через JDBC, которую можно использовать для практики этих API: https://github.com/oracle/oracle-db-examples/tree/master/java/AoJ. JavaDoc упоминается в README проект GitHub.

Ответ 16

Разрабатывается решение для обеспечения возможности реактивного подключения со стандартными реляционными базами данных.

Люди, желающие масштабировать при сохранении использования реляционных баз данных, отрезаны от реактивного программирования из-за существующих стандартов, основанных на блокировании ввода-вывода. R2DBC определяет новый API, который позволяет реактивному коду эффективно работать с реляционными базами данных.

R2DBC - это спецификация, разработанная с нуля для реактивного программирования с базами данных SQL, определяющая неблокирующий SPI для разработчиков драйверов баз данных и авторов клиентских библиотек. Драйверы R2DBC полностью реализуют проводной протокол базы данных поверх неблокирующего уровня ввода-вывода.

R2DBC WebSite

R2DBC GitHub

Функциональная матрица

enter image description here

Ответ 17

Некоторое простое решение - заключить ваши вызовы jdbs в CompletableFuture и предоставить пользовательский пул потоков для этих вызовов.