Ich frage mich, ob es eine Möglichkeit gibt, asynchrone Aufrufe an eine Datenbank zu tätigen.
Stellen Sie sich zum Beispiel vor, ich habe eine große Anfrage, deren Bearbeitung sehr lange dauert. Ich möchte die Anfrage senden und eine Benachrichtigung erhalten, wenn die Anfrage einen Wert zurückgibt (indem Sie einen Listener / Rückruf oder etwas anderes übergeben). Ich möchte das Warten auf die Antwort der Datenbank nicht blockieren.
Ich halte die Verwendung eines Thread-Pools nicht für eine Lösung, da diese nicht skaliert werden kann. Bei starken gleichzeitigen Anforderungen wird eine sehr große Anzahl von Threads erzeugt.
Wir sind mit solchen Problemen bei Netzwerkservern konfrontiert und haben Lösungen gefunden, indem wir den Systemaufruf select / poll / epoll verwenden, um zu vermeiden, dass ein Thread pro Verbindung vorhanden ist. Ich frage mich nur, wie ich eine ähnliche Funktion mit Datenbankanforderung haben kann.
Hinweis: Ich bin mir bewusst, dass die Verwendung eines FixedThreadPool eine gute Lösung sein kann, aber ich bin überrascht, dass niemand ein wirklich asynchrones System entwickelt hat (ohne die Verwendung eines zusätzlichen Threads).
** Update **
Aufgrund des Mangels an echten praktischen Lösungen habe ich beschlossen, selbst eine Bibliothek (Teil von finagle) zu erstellen: finagle-mysql . Grundsätzlich dekodiert / decodiert es MySQL-Anfragen / Antworten und verwendet Finagle / Netty unter der Haube. Es lässt sich auch bei einer großen Anzahl von Verbindungen sehr gut skalieren.
quelle
Antworten:
Ich verstehe nicht, wie einer der vorgeschlagenen Ansätze, die JDBC-Aufrufe in Akteure, Ausführende oder irgendetwas anderes einschließen, hier helfen kann - kann jemand klarstellen.
Das Grundproblem ist sicherlich, dass der JDBC-Operationsblock auf Socket-E / A blockiert. Wenn es dies tut, blockiert es den Thread, der am Ende der Geschichte läuft. Unabhängig davon, für welches Wrapping-Framework Sie sich entscheiden, wird ein Thread pro gleichzeitiger Anforderung beschäftigt / blockiert.
Wenn die zugrunde liegenden Datenbanktreiber (MySql?) Eine Möglichkeit bieten, die Socket-Erstellung abzufangen (siehe SocketFactory), kann ich mir vorstellen, dass eine asynchrone ereignisgesteuerte Datenbankebene auf der JDBC-API erstellt werden kann, die wir jedoch kapseln müssen ganze JDBC hinter einer ereignisgesteuerten Fassade, und diese Fassade würde nicht wie JDBC aussehen (nachdem sie ereignisgesteuert wäre). Die Datenbankverarbeitung würde in einem anderen Thread als dem Aufrufer asynchron erfolgen, und Sie müssten herausfinden, wie Sie einen Transaktionsmanager erstellen, der nicht auf der Thread-Affinität beruht.
So etwas wie der Ansatz, den ich erwähne, würde es sogar einem einzelnen Hintergrund-Thread ermöglichen, eine Ladung gleichzeitiger JDBC-Execs zu verarbeiten. In der Praxis würden Sie wahrscheinlich einen Thread-Pool ausführen, um mehrere Kerne zu verwenden.
(Natürlich kommentiere ich nicht die Logik der ursprünglichen Frage, sondern nur die Antworten, die implizieren, dass Parallelität in einem Szenario mit blockierendem Socket-E / A ohne den Benutzer eines Auswahlmusters möglich ist - einfacher, nur die typische JDBC-Parallelität zu berechnen und zu setzen in einem Verbindungspool der richtigen Größe).
Es sieht so aus, als ob MySql wahrscheinlich etwas in der von mir vorgeschlagenen Richtung tut --- http://code.google.com/p/async-mysql-connector/wiki/UsageExample
quelle
Es ist unmöglich, einen asynchronen Aufruf der Datenbank über JDBC zu tätigen , aber Sie können mit Actors asynchrone Aufrufe an JDBC mit Actors tätigen (z. B. ruft der Actor über DBBC die DB an und sendet Nachrichten an Dritte, wenn die Anrufe beendet sind). oder, wenn Sie CPS mögen, mit Pipeline-Futures (Versprechungen) (eine gute Implementierung ist Scalaz Promises )
Scala-Akteure sind standardmäßig ereignisbasiert (nicht threadbasiert). Durch die Fortführungsplanung können Millionen von Akteuren in einem Standard-JVM-Setup erstellt werden.
Wenn Sie auf Java abzielen, ist Akka Framework eine Actor-Modellimplementierung mit einer guten API sowohl für Java als auch für Scala.
Abgesehen davon macht die Synchronität von JDBC für mich vollkommen Sinn. Die Kosten für eine Datenbanksitzung sind weitaus höher als die Kosten für das Blockieren des Java-Threads (entweder im Vordergrund oder im Hintergrund) und das Warten auf eine Antwort. Wenn Ihre Abfragen so lange ausgeführt werden, dass die Funktionen eines Executor-Dienstes (oder das Umschließen von Actor / Fork-Join / Promise-Parallelitäts-Frameworks) nicht ausreichen (und Sie zu viele Threads verbrauchen), sollten Sie zunächst über Ihre nachdenken Datenbank laden. Normalerweise kommt die Antwort von einer Datenbank sehr schnell zurück, und ein Executor-Service, der mit einem festen Thread-Pool unterstützt wird, ist eine ausreichend gute Lösung. Wenn Sie zu viele lang laufende Abfragen haben, sollten Sie eine Vorverarbeitung (Vor-) Verarbeitung in Betracht ziehen - wie eine nächtliche Neuberechnung der Daten oder ähnliches.
quelle
Vielleicht könnten Sie ein asynchrones JMS-Nachrichtensystem verwenden, das sich ziemlich gut skalieren lässt, IMHO:
Senden Sie eine Nachricht an eine Warteschlange, in der die Abonnenten die Nachricht akzeptieren, und führen Sie den SQL-Prozess aus. Ihr Hauptprozess wird weiterhin ausgeführt und akzeptiert oder sendet neue Anforderungen.
Wenn der SQL-Prozess beendet ist, können Sie wie folgt vorgehen: Senden Sie eine Nachricht mit dem Ergebnis des Prozesses an eine ResponseQueue, und ein Listener auf der Clientseite akzeptiert sie und führt den Rückrufcode aus.
quelle
Es gibt keine direkte Unterstützung in JDBC, aber Sie haben mehrere Optionen wie MDB, Executors von Java 5.
"Ich halte die Verwendung eines Thread-Pools nicht für eine Lösung, da diese nicht skaliert werden kann. Bei starken gleichzeitigen Anforderungen wird eine sehr große Anzahl von Threads erzeugt."
Ich bin gespannt, warum ein begrenzter Pool von Threads nicht skaliert. Es ist ein Pool, der kein Thread pro Anforderung ist, um einen Thread pro Anforderung zu erzeugen. Ich benutze dies seit einiger Zeit auf einer Webapp mit hoher Last und wir haben bisher keine Probleme gesehen.
quelle
Es sieht so aus, als ob eine neue asynchrone JDBC-API "JDBC next" in Arbeit ist.
Siehe Präsentation hier
Sie können die API hier herunterladen
quelle
Wie in anderen Antworten erwähnt, ist die JDBC-API von Natur aus nicht asynchron.
Wenn Sie jedoch mit einer Teilmenge der Vorgänge und einer anderen API leben können, gibt es Lösungen. Ein Beispiel ist https://github.com/jasync-sql/jasync-sql , das für MySQL und PostgreSQL funktioniert.
quelle
Das Ajdbc-Projekt scheint dieses Problem zu lösen. Http://code.google.com/p/adbcj/
Derzeit gibt es 2 experimentelle nativ asynchrone Treiber für MySQL und Postgresql.
quelle
Eine alte Frage, aber noch mehr Informationen. Es ist nicht möglich, dass JDBC asynchrone Anforderungen an die Datenbank selbst ausgibt, es sei denn, ein Anbieter stellt eine Erweiterung für JDBC und einen Wrapper zur Verfügung, mit dem JDBC verarbeitet werden kann. Es ist jedoch möglich, JDBC selbst mit einer Verarbeitungswarteschlange zu versehen und eine Logik zu implementieren, die die Warteschlange auf einer oder mehreren separaten Verbindungen verarbeiten kann. Ein Vorteil für einige Arten von Aufrufen besteht darin, dass die Logik bei ausreichender Last die Aufrufe zur Verarbeitung in JDBC-Stapel konvertieren kann, was die Logik erheblich beschleunigen kann. Dies ist am nützlichsten für Anrufe, bei denen Daten eingefügt werden, und das tatsächliche Ergebnis muss nur protokolliert werden, wenn ein Fehler vorliegt. Ein gutes Beispiel hierfür ist, wenn Einfügungen durchgeführt werden, um Benutzeraktivitäten zu protokollieren. Die Bewerbung hat gewonnen '
Nebenbei bemerkt, ein Produkt auf dem Markt bietet einen richtliniengesteuerten Ansatz, um asynchrone Anrufe wie die von mir beschriebenen asynchron zu ermöglichen ( http://www.heimdalldata.com/ ). Haftungsausschluss: Ich bin Mitbegründer dieser Firma. Es ermöglicht die Anwendung regulärer Ausdrücke auf Datentransformationsanforderungen wie Einfügen / Aktualisieren / Löschen für jede JDBC-Datenquelle und stapelt diese automatisch zur Verarbeitung. Bei Verwendung mit MySQL und der Option rewriteBatchedStatements ( MySQL und JDBC mit rewriteBatchedStatements = true ) kann dies die Gesamtlast der Datenbank erheblich verringern .
quelle
Sie haben meiner Meinung nach drei Möglichkeiten:
Diclaimer: Ich bin einer der Entwickler von CoralMQ.
quelle
Es wird eine Lösung entwickelt, um reaktive Konnektivität mit relationalen Standarddatenbanken zu ermöglichen.
R2DBCs Website
GitHub von R2DBC
Funktionsmatrix
quelle
Die Java 5.0-Executoren könnten nützlich sein.
Sie können eine feste Anzahl von Threads haben, um lang laufende Vorgänge abzuwickeln. Und stattdessen
Runnable
können Sie verwendenCallable
, die ein Ergebnis zurückgeben. Das Ergebnis ist in einemFuture<ReturnType>
Objekt gekapselt , sodass Sie es abrufen können, wenn es zurück ist.quelle
Hier ist eine Übersicht darüber, wie eine nicht blockierende jdbc-API von Oracle aussehen könnte, die auf JavaOne vorgestellt wird: https://static.rainfocus.com/oracle/oow16/sess/1461693351182001EmRq/ppt/CONF1578%2020160916.pdf
Es scheint also, dass am Ende tatsächlich wirklich asynchrone JDBC-Aufrufe möglich sein werden.
quelle
Nur eine verrückte Idee: Sie könnten ein Iteratee-Muster über JBDC resultSet verwenden, das in eine Zukunft / ein Versprechen eingewickelt ist
Hammersmith macht das für MongoDB .
quelle
Ich denke hier nur an Ideen. Warum konnten Sie keinen Pool von Datenbankverbindungen haben, von denen jede einen Thread hat? Jeder Thread hat Zugriff auf eine Warteschlange. Wenn Sie eine Abfrage ausführen möchten, die lange dauert, können Sie sie in die Warteschlange stellen. Einer der Threads nimmt sie auf und verarbeitet sie. Sie werden nie zu viele Threads haben, da die Anzahl Ihrer Threads begrenzt ist.
Edit: Oder noch besser, nur eine Reihe von Threads. Wenn ein Thread etwas in einer Warteschlange sieht, fragt er nach einer Verbindung aus dem Pool und behandelt diese.
quelle
Die Bibliothek commons-dbutils unterstützt eine, für
AsyncQueryRunner
die Sie eine bereitstellenExecutorService
, und gibt eine zurückFuture
. Es lohnt sich, einen Blick darauf zu werfen, da es einfach zu bedienen ist und sicherstellt, dass keine Ressourcen verloren gehen.quelle
Wenn Sie an asynchronen Datenbank-APIs für Java interessiert sind, sollten Sie wissen, dass es eine neue Initiative gibt, um eine Reihe von Standard-APIs zu entwickeln, die auf CompletableFuture und Lambdas basieren. Es gibt auch eine Implementierung dieser APIs über JDBC, mit der diese APIs geübt werden können: https://github.com/oracle/oracle-db-examples/tree/master/java/AoJ Das JavaDoc wird in der README von erwähnt das Github-Projekt.
quelle