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

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

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

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

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

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

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


person Steve Gury    schedule 03.11.2010    source источник
comment
См. code.google.com/p/async-mysql-connector/wiki / UsageExample   -  person John Smith    schedule 30.09.2012
comment
См. Также github.com/mauricio/postgresql-async.   -  person Daniel Worthington-Bodart    schedule 14.08.2014
comment
Проблема в том, как БД может уведомить клиента о завершении запроса. Например, Oracle может использовать функцию уведомления об изменении результата запроса базы данных и получать уведомление при изменении данных db. Это относится к запросам SQL, которые изменяют данные базы данных. Для запросов только для чтения это не сработает. С другой стороны, я не уверен, что создание асинхронных подключений было бы хорошей идеей, поскольку их создание стоит дорого. Конечно, это не очень общее решение. Просто пища для размышлений ...   -  person Mike Argyriou    schedule 18.09.2015
comment
Использует ли finagle-mysql JDBC?   -  person Saeed Zarinfam    schedule 05.01.2017


Ответы (16)


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

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

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

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

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


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

person johnlon    schedule 30.09.2011
comment
Использование Akka не выполняет асинхронные вызовы реляционных БД. Это позволяет вам легко запускать их в группе выделенных потоков для доступа к БД. Таким образом, вы не отключаете весь сайт, когда он перестает отвечать на запросы, потому что вы всегда выполняете асинхронные вызовы на уровне обслуживания на уровень DAO с обещаниями, а потоки вашего веб-сервера отделены от остальной части вашего приложения. - person Onur; 18.05.2014
comment
Акторы - не единственные обходные пути (например, микросервисы и асинхронный http, который мы масштабируем до тысяч в секунду), и я бы не стал так быстро отвергать их как неасинхронные с точки зрения клиента. Если в вашу систему входит 1 тыс. Потоков пользовательского интерфейса, и только 10 потоков блокируются в БД, в то время как 990 «сообщений» (или что-то подобное) помещаются в очередь в памяти без блокировки любого из 1k потоков пользовательского интерфейса (которые, вероятно, будут выпущены) ... разве это не то, что требуется? Я хотел бы увидеть истинный асинхронный JDBC, но это не значит, что пока что нет чрезвычайно жизнеспособных обходных путей. - person Greg Pendlebury; 17.11.2015

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

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

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

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


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

person Vasil Remeniuk    schedule 03.11.2010
comment
+1. Я завернул дорогие вызовы JDBC (технически Querulous) в актеров и никогда не оглядывался назад. - person Max A.; 03.11.2010
comment
Я ориентируюсь на scala и хорошо знаком с шаблоном Promise / Actor. На самом деле я не рассматривал модель акторов, потому что я все еще хочу выполнять запросы параллельно, я не хочу иметь большого актора, который выполняет все мои запросы последовательно. Моя первая идея состояла в том, чтобы использовать Promises, поддерживаемые FixedThreadPool с тем же размером, что и количество подключений к db, в случае интенсивного использования каждый поток пула потоков блокируется в ожидании db. Что меня раздражает, так это то, что нет необходимости во всех этих потоках, было бы вполне возможно иметь эквивалентную систему только с одним потоком. - person Steve Gury; 04.11.2010
comment
Стив, просто создайте нового актера для каждого звонка? - person Viktor Klang; 05.11.2010
comment
@Victor, каждый субъект, работающий параллельно над блокирующей операцией (JDBC), будет работать в отдельном потоке, которого Стив пытается избежать. - person Vasil Remeniuk; 06.11.2010
comment
Подход актора по-прежнему требует одного потока для каждой активной транзакции базы данных, пока транзакция выполняется, так что это не совсем решение проблемы OP, если вы не хотите ограничивать количество параллельных транзакций базы данных и не выполнять некоторые операции с асинхронной базой данных, ожидающие некоторых уже выполняющие их, чтобы завершить и освободить поток. Тем не менее, это неплохая идея - база данных может быть перегружена, если вы откроете слишком много подключений, поэтому размещение транзакции базы данных в очереди для обработки вместо блокировки потока обработки HTTP-запроса поможет. - person Dobes Vandermeer; 20.03.2012
comment
Я не думаю, что это невозможно ... code.google.com/p/ async-mysql-connector / wiki / UsageExample - говоря, что мне еще предстоит опробовать код ... - person John Smith; 30.09.2012
comment
Решение на основе акторов все еще блокирует поток. Не говорите, что невозможно выполнить вызов async jdbc, существуют экспериментальные библиотеки с открытым исходным кодом, которые пытаются реализовать async jdbc. - person ; 04.10.2013
comment
+1 Стоимость сеанса базы данных намного выше, чем стоимость блокируемого потока Java. - person Paul Draper; 23.04.2014
comment
Для дорогостоящих обращений к БД обычно не возникает такой большой проблемы. Когда вызов является тривиальным, накладные расходы сети становятся проблемой. Если вы хотите сделать 100 запросов, каждый из которых занимает 1 мс в БД, но накладные расходы сети составляют 200 мс, тогда это займет более 20 секунд синхронно, но будет занимать 300 мс асинхронно. - person morten; 18.12.2017
comment
The cost of a database session is far higher than the cost of the Java thread being blocked (either in the fore- or background) and waiting for a response - Это необоснованное утверждение. Я вспоминаю теперь, спустя столько лет, учитывая, что это был первый вопрос, который я увидел по stackoverflow! - person Unmanned Player; 13.01.2021

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

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

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

person Tomas Narros    schedule 03.11.2010

Похоже, теперь в разработке новый асинхронный jdbc API JDBC.

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

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

Обновление:

  • Этот новый API jdbc позже был назван ADBA. Затем, в сентябре 2019 года, работа была остановлена. см. Список рассылки сообщение.
  • R2DBC, похоже, достигает аналогичных целей. Он уже поддерживает большинство основных баз данных (кроме oracle db). Обратите внимание, что этот проект является библиотекой, а не частью jdk.
person Sebastien    schedule 19.03.2018
comment
перенаправленная ссылка, указывающая на более позднюю реализацию, находится здесь: oracle.com/goto/java-async -db - person Remigius Stalder; 05.04.2018

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

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

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

person Aravind Yarram    schedule 03.11.2010
comment
Я думаю, что главный аргумент против потоков заключается в том, что вы фактически находитесь за пределами любых стандартных ограничений Java-контейнеров, поэтому вы теряете управляемую контейнером кластеризацию и возможности аварийного переключения, хотя вы можете свернуть свои собственные или использовать что-то вроде Terracotta. - person mezmo; 03.11.2010
comment
мы можем подключиться к опросам потоков, управляемых сервером приложений, с помощью диспетчеров работы. websphere, weblogic и glassfish поддерживают его - person Aravind Yarram; 03.11.2010

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

person oshai    schedule 09.09.2018

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

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

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

Веб-сайт R2DBC

GitHub R2DBC

Матрица функций

введите здесь описание изображения

person Yassin Hajaj    schedule 15.06.2019

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

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

person Sebastien    schedule 03.05.2013
comment
Хотелось бы, чтобы такой подход был готов. JDBC сильно изменился с самого начала (итераторы, шаблоны, подготовленные процедуры), но этот асинхронный подход никогда не реализовывался. Это было бы особенно интересно для операций записи (Insert, Update, Delete), и особенно для тех тяжелых пакетных операций передачи, с которыми мы все сталкиваемся. На мой взгляд, любой клиентский подход (пул, субъект, планирование, обмен сообщениями ...) приведет к небольшому вознаграждению с точки зрения использования ресурсов (возможно, некоторого выигрыша в пропускной способности или задержке). - person Jaime Casero; 15.04.2015
comment
Старый и заброшенный, поддерживается только два типа данных и даже близко не готов к производству. К несчастью :( - person Aaron Zinman; 10.06.2015
comment
Проблема №1 этой библиотеки связана с недоступностью веб-сайта. Ему больше года. Я подозреваю, что эта библиотека мертва. - person Lukas Eder; 15.06.2015

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

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

person Erik Brandsberg    schedule 30.11.2015
comment
Но это по-прежнему означает, что JDBC должен иметь хотя бы один отдельный поток. А как насчет однопоточных фреймворков и стеков, которые по-прежнему основаны на обратных вызовах (на ум приходит nodejs)? Вы знаете, как они управляют вызовами JDBC? - person yuranos; 14.06.2017

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

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

Заявитель: Я один из разработчиков CoralMQ.

person rdalmeida    schedule 09.02.2016

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

У вас может быть фиксированное количество потоков для обработки длительных операций. И вместо Runnable вы можете использовать Callable, который возвращает результат. Результат инкапсулируется в _3 _, чтобы вы могли получить его, когда он вернется.

person Bozho    schedule 04.11.2010

Вот схема того, как может выглядеть неблокирующий jdbc api из Oracle, представленного на JavaOne: https://static.rainfocus.com/oracle/oow16/sess/1461693351182001EmRq/ppt/CONF1578%2020160916.pdf

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

person nemoo    schedule 23.11.2017
comment
Это не JDBC, а дополнительный API - person yaccob; 03.07.2018

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

Hammersmith делает это для MongoDB.

person jwinandy    schedule 04.08.2011

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

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

person Amir Raminfar    schedule 03.11.2010

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

person William Speirs    schedule 23.11.2011

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

person Jean de Lavarene    schedule 12.04.2018