Возможен ли асинхронный вызов jdbc? - PullRequest
148 голосов
/ 03 ноября 2010

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

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

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

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

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

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

Ответы [ 17 ]

156 голосов
/ 01 октября 2011

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

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

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

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

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


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

41 голосов
/ 03 ноября 2010

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

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

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

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


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

10 голосов
/ 03 ноября 2010

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

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

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

7 голосов
/ 03 ноября 2010

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

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

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

4 голосов
/ 19 марта 2018

Похоже, новый асинхронный jdbc API "JDBC next" находится в разработке.

См. Презентацию здесь

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

4 голосов
/ 10 сентября 2018

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

3 голосов
/ 04 мая 2013

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

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

3 голосов
/ 09 февраля 2016

У вас есть три варианта на мой взгляд:

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

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

3 голосов
/ 01 декабря 2015

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

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

2 голосов
/ 04 ноября 2010

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

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

...