Zastanawiam się, czy istnieje sposób na wykonywanie asynchronicznych wywołań do bazy danych?
Na przykład wyobraź sobie, że mam duże żądanie, którego przetworzenie zajmuje bardzo dużo czasu, chcę wysłać żądanie i otrzymać powiadomienie, gdy żądanie zwróci wartość (przekazując Listener / callback lub coś w tym rodzaju). Nie chcę blokować czekania na odpowiedź bazy danych.
Nie uważam, że użycie puli wątków jest rozwiązaniem, ponieważ nie jest skalowalne, w przypadku ciężkich współbieżnych żądań spowoduje to powstanie bardzo dużej liczby wątków.
Mamy do czynienia z tego rodzaju problemem z serwerami sieciowymi i znaleźliśmy rozwiązania za pomocą wywołania systemowego select / poll / epoll, aby uniknąć posiadania jednego wątku na połączenie. Zastanawiam się tylko, jak mieć podobną funkcję z żądaniem bazy danych?
Uwaga: zdaję sobie sprawę, że użycie FixedThreadPool może być dobrym obejściem, ale jestem zaskoczony, że nikt nie opracował systemu naprawdę asynchronicznego (bez użycia dodatkowego wątku).
** Aktualizacja **
Ze względu na brak realnych praktycznych rozwiązań postanowiłem sam stworzyć bibliotekę (część finagle): finagle-mysql . Zasadniczo dekoduje / dekoduje żądanie / odpowiedź mysql i używa Finagle / Netty pod maską. Bardzo dobrze skaluje się nawet przy dużej liczbie połączeń.
źródło
Odpowiedzi:
Nie rozumiem, w jaki sposób którekolwiek z proponowanych podejść, które zawijają wywołania JDBC w aktorach, wykonawcach lub cokolwiek innego, może tutaj pomóc - czy ktoś może to wyjaśnić.
Z pewnością podstawowym problemem jest blokowanie operacji JDBC na gnieździe IO. Kiedy to robi, blokuje uruchamianie wątku - koniec historii. Niezależnie od wybranego frameworka zawijania, jeden wątek będzie zajęty / zablokowany na współbieżne żądanie.
Jeśli podstawowe sterowniki bazy danych (MySql?) Oferują sposób przechwycenia tworzenia gniazda (patrz SocketFactory), wyobrażam sobie, że byłoby możliwe zbudowanie warstwy bazy danych sterowanej zdarzeniami asynchronicznymi na wierzchu interfejsu API JDBC, ale musielibyśmy hermetyzować całe JDBC za fasadą sterowaną wydarzeniami, a ta fasada nie wyglądałaby jak JDBC (po tym, jak byłaby sterowana zdarzeniami). Przetwarzanie bazy danych odbywałoby się asynchronicznie w innym wątku z wywołującym i musiałbyś wymyślić, jak zbudować menedżera transakcji, który nie opiera się na koligacji wątków.
Coś podobnego do podejścia, o którym wspomniałem, pozwoliłoby nawet pojedynczemu wątkowi w tle na przetworzenie obciążenia równoczesnych plików exec JDBC. W praktyce prawdopodobnie uruchomiłbyś pulę wątków, aby wykorzystać wiele rdzeni.
(Oczywiście nie komentuję logiki pierwotnego pytania tylko odpowiedzi, które sugerują, że współbieżność w scenariuszu z blokowaniem wejścia / wyjścia gniazda jest możliwa bez użytkownika wzorca selektora - prostsze jest po prostu obliczenie typowej współbieżności JDBC i umieszczenie w puli połączeń o odpowiedniej wielkości).
Wygląda na to, że MySql prawdopodobnie robi coś podobnego do sugerowanego przeze mnie --- http://code.google.com/p/async-mysql-connector/wiki/UsageExample
źródło
Nie można wykonać asynchronicznego wywołania do bazy danych przez JDBC, ale można wykonywać asynchroniczne wywołania do JDBC za pomocą Actors (np. Aktor wykonuje wywołania bazy danych przez JDBC i wysyła wiadomości do osób trzecich, gdy połączenia się kończą), lub, jeśli lubisz CPS, z potokowymi kontraktami futures (obietnicami) (dobrą implementacją jest Scalaz Promises )
Aktorzy Scala są domyślnie oparte na zdarzeniach (a nie na wątkach) - planowanie kontynuacji umożliwia tworzenie milionów aktorów w standardowej konfiguracji JVM.
Jeśli celujesz w Javę, Akka Framework to implementacja modelu Actor, która ma dobry interfejs API zarówno dla języka Java, jak i Scala.
Poza tym synchroniczna natura JDBC ma dla mnie sens. Koszt sesji bazy danych jest znacznie wyższy niż koszt zablokowania wątku Java (w tle lub w tle) i oczekiwania na odpowiedź. Jeśli Twoje zapytania działają tak długo, że możliwości usługi wykonawczej (lub zawijania struktur współbieżności Actor / fork-join / promise) nie są dla Ciebie wystarczające (i zużywasz zbyt wiele wątków), powinieneś przede wszystkim pomyśleć o ładowanie bazy danych. Zwykle odpowiedź z bazy danych wraca bardzo szybko, a usługa wykonawcza wspierana przez stałą pulę wątków jest wystarczająco dobrym rozwiązaniem. Jeśli masz zbyt wiele długo działających zapytań, powinieneś rozważyć wstępne (wstępne) przetwarzanie - na przykład nocne przeliczanie danych lub coś w tym rodzaju.
źródło
Być może przydałby się asynchroniczny system przesyłania wiadomości JMS, który całkiem dobrze się skaluje, IMHO:
Wyślij wiadomość do kolejki, gdzie subskrybenci zaakceptują wiadomość i uruchomią proces SQL. Twój główny proces będzie nadal działać i będzie akceptować lub wysyłać nowe żądania.
Po zakończeniu procesu SQL możesz uruchomić go w odwrotny sposób: wysłać wiadomość do ResponseQueue z wynikiem procesu, a odbiornik po stronie klienta zaakceptuje go i uruchom kod wywołania zwrotnego.
źródło
Nie ma bezpośredniego wsparcia w JDBC, ale masz wiele opcji, takich jak MDB, Executory z Java 5.
„Nie uważam, że użycie puli wątków jest rozwiązaniem, ponieważ nie jest skalowalne. W przypadku wielu jednoczesnych żądań spowoduje to powstanie bardzo dużej liczby wątków”.
Ciekawi mnie, dlaczego ograniczona pula wątków nie miałaby się skalować? Jest to pula, a nie wątek na żądanie, służąca do tworzenia wątku na każde żądanie. Używam tego od jakiegoś czasu na mocno obciążonej aplikacji internetowej i do tej pory nie widzieliśmy żadnych problemów.
źródło
Wygląda na to, że pracujemy nad nowym asynchronicznym interfejsem API jdbc „JDBC next”.
Zobacz prezentację tutaj
Możesz pobrać API stąd
źródło
Jak wspomniano w innych odpowiedziach, JDBC API nie jest z natury asynchroniczne.
Jeśli jednak możesz żyć z podzbiorem operacji i innym interfejsem API, istnieją rozwiązania. Jednym z przykładów jest https://github.com/jasync-sql/jasync-sql, który działa dla MySQL i PostgreSQL.
źródło
Projekt Ajdbc wydaje się odpowiadać na ten problem http://code.google.com/p/adbcj/
Obecnie istnieją 2 eksperymentalne sterowniki natywnie asynchroniczne dla mysql i postgresql.
źródło
Stare pytanie, ale trochę więcej informacji. Nie jest możliwe, aby JDBC wysyłał asynchroniczne żądania do samej bazy danych, chyba że dostawca zapewni rozszerzenie JDBC i opakowanie do obsługi JDBC. To powiedziawszy, możliwe jest owinięcie samego JDBC kolejką przetwarzania i zaimplementowanie logiki, która może przetwarzać poza kolejką w jednym lub większej liczbie oddzielnych połączeń. Jedną z zalet tego w przypadku niektórych typów wywołań jest to, że logika, jeśli jest wystarczająco obciążona, może konwertować wywołania na partie JDBC do przetwarzania, co może znacznie przyspieszyć logikę. Jest to najbardziej przydatne w przypadku połączeń, w których wstawiane są dane, a rzeczywisty wynik musi zostać zarejestrowany tylko w przypadku wystąpienia błędu. Doskonałym tego przykładem jest sytuacja, w której operacje wstawiania są wykonywane w celu rejestrowania aktywności użytkownika. Aplikacja wygrała ”
Na marginesie, jeden produkt na rynku zapewnia podejście oparte na polityce, pozwalające na asynchroniczne wykonywanie wywołań asynchronicznych, takich jak te, które opisałem ( http://www.heimdalldata.com/ ). Zastrzeżenie: jestem współzałożycielem tej firmy. Umożliwia stosowanie wyrażeń regularnych do żądań transformacji danych, takich jak wstawianie / aktualizowanie / usuwanie dowolnego źródła danych JDBC, i automatycznie łączy je w partie w celu przetworzenia. W połączeniu z MySQL i opcją rewriteBatchedStatements ( MySQL i JDBC z rewriteBatchedStatements = true ) może to znacznie zmniejszyć ogólne obciążenie bazy danych.
źródło
Moim zdaniem masz trzy opcje:
Diclaimer: Jestem jednym z twórców CoralMQ.
źródło
Opracowywane jest rozwiązanie umożliwiające reaktywną łączność ze standardowymi relacyjnymi bazami danych.
Witryna internetowa R2DBC
GitHub R2DBC
Matryca funkcji
źródło
W Java 5,0 wykonawcy może się przydać.
Możesz mieć stałą liczbę wątków do obsługi długotrwałych operacji. I zamiast
Runnable
ciebie możesz użyćCallable
, które zwracają wynik. Wynik jest zamknięty wFuture<ReturnType>
obiekcie, dzięki czemu można go uzyskać, gdy wróci.źródło
Oto zarys tego, jak może wyglądać nieblokujący interfejs jdbc api firmy Oracle przedstawiony na JavaOne: https://static.rainfocus.com/oracle/oow16/sess/1461693351182001EmRq/ppt/CONF1578%2020160916.pdf
Wydaje się więc, że w końcu prawdziwie asynchroniczne wywołania JDBC będą rzeczywiście możliwe.
źródło
Po prostu szalony pomysł: możesz użyć wzorca Iteratee zamiast zestawu wyników JBDC zawiniętego w trochę Future / Promise
Hammersmith robi to dla MongoDB .
źródło
Myślę tutaj o pomysłach. Dlaczego nie można mieć puli połączeń z bazą danych, z których każde ma wątek. Każdy wątek ma dostęp do kolejki. Jeśli chcesz wykonać zapytanie, które zajmuje dużo czasu, możesz umieścić w kolejce, a wtedy jeden z wątków podejmie je i obsłuży. Nigdy nie będziesz mieć zbyt wielu wątków, ponieważ liczba Twoich wątków jest ograniczona.
Edycja: Lub jeszcze lepiej, tylko kilka wątków. Gdy wątek widzi coś w kolejce, prosi o połączenie z puli i obsługuje je.
źródło
Biblioteka commons-dbutils obsługuje plik,
AsyncQueryRunner
który podajeszExecutorService
do, i zwraca plikFuture
. Warto to sprawdzić, ponieważ jest łatwy w użyciu i zapewnia, że nie wycieknie zasoby.źródło
Jeśli jesteś zainteresowany asynchronicznymi interfejsami API baz danych dla języka Java, powinieneś wiedzieć, że pojawiła się nowa inicjatywa polegająca na opracowaniu zestawu standardowych interfejsów API opartych na CompletableFuture i lambdach. Istnieje również implementacja tych interfejsów API przez JDBC, której można użyć do ćwiczenia tych interfejsów API: https://github.com/oracle/oracle-db-examples/tree/master/java/AoJ JavaDoc jest wymieniona w pliku README projekt github.
źródło