Интересно, есть ли способ совершать асинхронные вызовы к базе данных?
Например, представьте, что у меня большой запрос, который обрабатывается очень долго, я хочу отправить запрос и получить уведомление, когда запрос вернет значение (путем передачи Listener / callback или чего-то еще). Я не хочу блокировать ожидание ответа базы данных.
Я не считаю, что использование пула потоков - это решение, потому что оно не масштабируется, в случае тяжелых параллельных запросов это породит очень большое количество потоков.
Мы сталкиваемся с такого рода проблемами с сетевыми серверами, и мы нашли решения, используя системный вызов select / poll / epoll, чтобы избежать использования одного потока на соединение. Мне просто интересно, как иметь подобную функцию с запросом к базе данных?
Примечание: я знаю, что использование FixedThreadPool может быть хорошим обходным путем, но я удивлен, что никто не разработал систему действительно асинхронную (без использования дополнительного потока).
** Обновление **
Из-за отсутствия реальных практических решений я решил сам создать библиотеку (часть finagle): finagle-mysql . Он в основном декодирует / декодирует запрос / ответ mysql и использует Finagle / Netty под капотом. Он отлично масштабируется даже при огромном количестве соединений.
источник
Ответы:
Я не понимаю, как какой-либо из предложенных подходов, которые заключают в себе вызовы JDBC в Actors, executors или чем-то еще, может помочь здесь - может кто-то прояснить.
Конечно, основная проблема заключается в том, что операции JDBC блокируются на сокете ввода-вывода. Когда он делает это, он блокирует поток, продолжающий историю. Независимо от того, какую оболочку вы выберете, вы будете использовать один поток, который будет занят / заблокирован для одновременного запроса.
Если базовые драйверы базы данных (MySql?) Предлагают средства для перехвата создания сокета (см. SocketFactory), то я полагаю, что было бы возможно создать асинхронный управляемый событиями слой базы данных поверх API JDBC, но нам пришлось бы инкапсулировать весь JDBC за фасадом, управляемым событиями, и этот фасад не будет выглядеть как JDBC (после того, как он будет управляться событиями). Обработка базы данных будет происходить асинхронно в другом потоке к вызывающей стороне, и вам нужно будет решить, как создать диспетчер транзакций, который не зависит от привязки потока.
Нечто подобное описанному мною подходу позволило бы даже одному фоновому потоку обрабатывать загрузку одновременных JDBC-исполняемых файлов. На практике вы, вероятно, запустите пул потоков, чтобы использовать несколько ядер.
(Конечно, я не комментирую логику исходного вопроса, а просто ответы, которые подразумевают, что параллелизм в сценарии с блокировкой ввода-вывода сокетов возможен без пользователя шаблона селектора - проще просто проработать свой типичный JDBC-параллелизм и поместить в пуле соединений нужного размера).
Похоже, что MySql, вероятно, делает что-то вроде того, что я предлагаю --- http://code.google.com/p/async-mysql-connector/wiki/UsageExample
источник
Невозможно сделать асинхронный вызов к базе данных через JDBC, но вы можете делать асинхронные вызовы в JDBC с помощью Actors (например, actor делает вызовы в DB через JDBC и отправляет сообщения третьим сторонам, когда вызовы завершены), или, если вам нравится CPS, с конвейерными фьючерсами (обещаниями) (хорошая реализация - Scalaz Promises )
Акторы Scala по умолчанию основаны на событиях (а не на потоках) - планирование продолжения позволяет создавать миллионы акторов при стандартной настройке JVM.
Если вы ориентируетесь на Java, Akka Framework - это реализация модели Actor, которая имеет хороший API как для Java, так и для Scala.
Кроме того, синхронный характер JDBC имеет для меня прекрасный смысл. Стоимость сеанса базы данных намного выше, чем стоимость блокировки потока Java (в фоновом или фоновом режиме) и ожидания ответа. Если ваши запросы выполняются так долго, что возможностей службы-исполнителя (или обертывания сред параллелизма Actor / fork-join / обещание) вам недостаточно (и вы используете слишком много потоков), вам следует прежде всего подумать о своем загрузка базы данных. Обычно ответ из базы данных возвращается очень быстро, и служба исполнителя, поддерживаемая фиксированным пулом потоков, является достаточно хорошим решением. Если у вас слишком много долго выполняющихся запросов, вам следует рассмотреть предварительную (предварительную) обработку - например, ночной пересчет данных или что-то в этом роде.
источник
Возможно, вы могли бы использовать систему асинхронного обмена сообщениями JMS, которая хорошо масштабируется, IMHO:
Отправьте сообщение в очередь, где подписчики примут сообщение, и запустите процесс SQL. Ваш основной процесс будет продолжать работать и принимать или отправлять новые запросы.
Когда процесс SQL завершается, вы можете запустить противоположный путь: отправить сообщение в ResponseQueue с результатом процесса, а слушатель на стороне клиента примет его и выполнит код обратного вызова.
источник
В JDBC нет прямой поддержки, но у вас есть несколько вариантов, таких как MDB, Executors from Java 5.
«Я не считаю, что использование пула потоков - это решение, потому что оно не масштабируется, в случае тяжелых параллельных запросов это породит очень большое количество потоков».
Мне интересно, почему ограниченный пул потоков не собирается масштабироваться? Это пул, а не поток по запросу, порождающий поток для каждого запроса. Я использовал это в течение довольно долгого времени в веб-приложении с большой нагрузкой, и мы пока не видели никаких проблем.
источник
Похоже, новый асинхронный jdbc API "JDBC next" находится в разработке.
Посмотреть презентацию здесь
Вы можете скачать API здесь
источник
Как уже упоминалось в других ответах, JDBC API не является асинхронным по своей природе.
Однако, если вы можете жить с подмножеством операций и другим API, есть решения. Одним из примеров является https://github.com/jasync-sql/jasync-sql, который работает для MySQL и PostgreSQL.
источник
Проект Ajdbc, кажется, решает эту проблему http://code.google.com/p/adbcj/
В настоящее время есть 2 экспериментальных асинхронных драйвера для mysql и postgresql.
источник
Старый вопрос, но еще немного информации. Невозможно, чтобы JDBC выдавал асинхронные запросы к самой базе данных, если только поставщик не предоставил расширение JDBC и оболочку для обработки JDBC. Тем не менее, можно обернуть сам JDBC в очередь обработки и реализовать логику, которая может обрабатывать очередь в одном или нескольких отдельных соединениях. Одним из преимуществ этого для некоторых типов вызовов является то, что логика, если она находится под достаточно большой нагрузкой, может преобразовывать вызовы в пакеты JDBC для обработки, что может значительно ускорить логику. Это наиболее полезно для вызовов, в которые вставляются данные, а фактический результат необходимо регистрировать только в случае ошибки. Прекрасным примером этого является, если вставки выполняются для регистрации активности пользователя. Приложение выиграло
В качестве дополнительного примечания, один продукт на рынке обеспечивает политический подход к разрешению асинхронных вызовов, подобных тем, которые я описал, для асинхронного выполнения ( http://www.heimdalldata.com/ ). Отказ от ответственности: я являюсь соучредителем этой компании. Он позволяет применять регулярные выражения к запросам преобразования данных, таким как вставка / обновление / удаление для любого источника данных JDBC, и автоматически объединяет их вместе для обработки. При использовании с MySQL и опцией rewriteBatchedStatements ( MySQL и JDBC с rewriteBatchedStatements = true ) это может значительно снизить общую нагрузку на базу данных.
источник
У вас есть три варианта на мой взгляд:
Диклаймер: Я один из разработчиков CoralMQ.
источник
Разрабатывается решение для обеспечения возможности реактивного подключения со стандартными реляционными базами данных.
Сайт R2DBC
GitHub R2DBC
Функциональная матрица
источник
Исполнители Java 5.0 могут пригодиться.
Вы можете иметь фиксированное количество потоков для обработки длительных операций. И вместо
Runnable
вас можно использоватьCallable
, которые возвращают результат. Результат инкапсулирован вFuture<ReturnType>
объект, так что вы можете получить его, когда он вернется.источник
Вот краткое описание того, как неблокируемый API jdbc может выглядеть из Oracle, представленного на JavaOne: https://static.rainfocus.com/oracle/oow16/sess/1461693351182001EmRq/ppt/CONF1578%2020160916.pdf
Таким образом, кажется, что в конечном итоге действительно асинхронные вызовы JDBC будут действительно возможны.
источник
Просто сумасшедшая идея: вы можете использовать шаблон Iteratee над JBDC resultSet, завернутый в некое Future / Promise
Хаммерсмит делает это для MongoDB .
источник
Я просто думаю об идеях здесь. Почему вы не можете иметь пул соединений с базой данных, каждый из которых имеет поток. Каждый поток имеет доступ к очереди. Если вы хотите выполнить запрос, который занимает много времени, вы можете поставить его в очередь, и тогда один из потоков подберет его и обработает. У вас никогда не будет слишком много потоков, потому что количество ваших потоков ограничено.
Изменить: Или еще лучше, просто несколько потоков. Когда поток видит что-то в очереди, он запрашивает соединение из пула и обрабатывает его.
источник
Библиотека commons-dbutils имеет поддержку для
AsyncQueryRunner
которой вы предоставляете,ExecutorService
и она возвращаетFuture
. Стоит проверить, так как он прост в использовании и гарантирует, что вы не потеряете ресурсы.источник
Если вас интересуют API-интерфейсы для асинхронных баз данных для Java, вы должны знать, что появилась новая инициатива по разработке набора стандартных API-интерфейсов, основанных на CompletableFuture и lambdas. Существует также реализация этих API через JDBC, которую можно использовать для практики этих API: https://github.com/oracle/oracle-db-examples/tree/master/java/AoJ . JavaDoc упоминается в README проект GitHub.
источник