L'appel asynchrone jdbc est-il possible?

je me demande s'il y a un moyen de faire des appels asynchrones à une base de données?

par exemple, imaginez que j'ai une grosse requête qui prend beaucoup de temps à traiter, Je veux envoyer la requête et recevoir une notification quand la requête retournera une valeur (en passant un écouteur/rappel ou quelque chose). Je ne veux pas bloquer en attendant que la base de données réponde.

Je ne considère pas que l'utilisation d'un pool de threads est une solution parce qu'il ne scale, dans le cas de requêtes concurrentes lourdes, cela générera un très grand nombre de threads.

nous sommes confrontés à ce type de problème avec les serveurs réseau et nous avons trouvé des solutions en utilisant select/poll/epoll appel système pour éviter d'avoir un thread par connexion. Je me demande juste comment avoir une fonctionnalité similaire avec une requête de base de données?

Note: Je suis conscient que L'utilisation D'un FixedThreadPool peut être une bonne solution de rechange, mais je suis surpris que personne n'a développé un système asynchrone (sans l'utilisation de fil supplémentaire).

** mise à Jour **

Faute de solutions pratiques, j'ai décidé de créer moi-même une bibliothèque (faisant partie de finagle): finagle-mysql . Il décode / décode essentiellement mysql demande / réponse, et utiliser Finagle/Netty sous la hotte. Il balance extrêmement bien même avec un grand nombre de connexions.

132
demandé sur Steve Gury 2010-11-03 16:52:18

16 réponses

Je ne comprends pas comment l'une des approches proposées qui enveloppent les appels JDBC dans des acteurs, des exécuteurs ou quoi que ce soit d'autre peut aider ici - quelqu'un peut clarifier.

sûrement le problème de base est que les opérations JDBC bloquent sur socket IO. Quand il le fait, il bloque le fil son fonctionnement sur-fin de l'histoire. Quel que soit le framework d'enrubannage que vous choisissez d'utiliser, il se terminera par un thread maintenu occupé/bloqué par requête concurrente.

si la les pilotes de base de données sous-jacents (MySql?) offre un moyen d'intercepter la création de socket (voir SocketFactory) alors j'imagine qu'il serait possible de construire une couche de base de données asynchrone basée sur les événements au-dessus de L'api JDBC, mais nous aurions à encapsuler l'ensemble de JDBC derrière une façade basée sur les événements, et cette façade ne ressemblerait pas à JDBC (après qu'elle serait basée sur les événements). Le traitement de la base de données se produirait async sur un fil différent à l'appelant, et vous auriez à travailler sur la façon de construire une transaction gestionnaire qui ne s'appuie pas sur l'affinité de thread.

quelque chose comme l'approche que je mentionne permettrait même un seul thread de fond pour traiter une charge de JDBC exec concurrents. Dans la pratique, vous lanceriez probablement un pool de threads pour faire usage de plusieurs noyaux.

(bien sûr, je ne commente pas sur la logique de la question d'origine juste les réponses qui impliquent que la concurrence dans un scénario avec blocage socket IO est possible sans l'utilisateur d'un modèle de sélecteur-plus simple juste pour calculer votre concurrence typique JDBC et mettre dans un pool de connexion de la bonne taille).


on dirait que MySql fait probablement quelque chose dans le sens que je suggère --- http://code.google.com/p/async-mysql-connector/wiki/UsageExample

141
répondu johnlon 2011-09-30 21:15:40

il est impossible de faire un appel asynchrone à la base de données via JDBC, mais vous pouvez faire des appels asynchrones à JDBC avec Actors (par exemple, acteur fait des appels à la DB via JDBC, et envoie des messages aux Tiers, lorsque les appels sont terminés), ou, si vous aimez CPS, avec Pipelined futures (promises) (une bonne implémentation est Scalaz Promesses )

Je ne considère pas que l'utilisation d'un pool de threads est une solution parce qu'il ne scale pas, dans le cas de requêtes concurrentes lourdes, cela va engendrer un très grand nombre de threads.

les acteurs Scala par défaut sont basés sur les événements (pas sur les threads)-la planification de la continuation permet de créer des millions d'acteurs sur une configuration JVM standard.

si vous ciblez Java, Akka Framework est un acteur model implementation qui a une bonne API à la fois pour Java et Scala.


mis à part cela, la nature synchrone de JDBC me semble parfaitement logique. Le coût d'une session de base de données est beaucoup plus élevé que le coût du thread Java bloqué (soit dans l'avant - plan ou l'arrière-plan) et en attente d'une réponse. Si vos requêtes sont si longues que les possibilités d'un service d'exécuteur testamentaire (ou wrapping acteur/fork-join / promise concordency frameworks) ne sont pas assez pour vous (et vous consommez trop de threads), vous devriez d'abord penser à votre chargement de base de données. Normalement, la réponse d'une base de données revient très rapidement, et un service d'exécuteur appuyé avec un pool de threads fixe est une bonne solution. Si vous avez trop de requêtes en cours d'exécution, vous devriez envisager un traitement initial (pré-)comme le recalcul nocturne des données ou quelque chose comme ça.

38
répondu Vasil Remeniuk 2012-05-03 19:23:21

peut-être pourriez-vous utiliser un système de messagerie asynchrone JMS, qui se balance assez bien, IMHO:

  • envoyer un message à une file d'attente, où les abonnés accepteront le message, et exécuter le processus SQL. Votre processus principal continuera d'exécuter et d'accepter ou d'envoyer de nouvelles demandes.

  • lorsque le processus SQL se termine, vous pouvez exécuter le chemin inverse: envoyer un message à un responsable avec le résultat de le processus, et un auditeur du côté client l'acceptent et exécutent le code de rappel.

11
répondu Tomas Narros 2011-10-27 19:14:08

il n'y a pas de support direct dans JDBC mais vous avez plusieurs options comme MDB, exécuteurs de Java 5.

" Je ne considère pas que l'utilisation d'un pool de threads est une solution parce qu'il ne scale pas, dans le cas de requêtes concurrentes lourdes, cela va engendrer un très grand nombre de threads."

je suis curieux de savoir pourquoi un bassin limité de fils ne va pas à l'échelle? C'est une piscine pas thread-par-requête pour frayer un thread pour chaque demande. J'ai été en utilisant cela pendant un certain temps sur une webapp lourde charge et nous n'avons pas vu de problèmes jusqu'à présent.

7
répondu Aravind R. Yarram 2010-11-03 13:55:23

le Java 5.0 executors pourrait s'avérer pratique.

Vous pouvez avoir un nombre fixe de threads pour gérer les opérations de longue durée. Et au lieu de Runnable vous pouvez utiliser Callable , qui renvoient un résultat. Le résultat est encapsulé dans un objet Future<ReturnType> , de sorte que vous pouvez l'obtenir quand il est de retour.

3
répondu Bozho 2010-11-04 09:39:19

Ajdbc projet semble répondre à ce problème http://code.google.com/p/adbcj/

il y a actuellement 2 pilotes asynchrones expérimentaux pour mysql et postgresql.

3
répondu Sebastien 2013-05-03 22:50:28

une vieille question, mais plus d'informations. Il n'est pas possible que JDBC émette des requêtes asynchrones à la base de données elle-même, à moins qu'un fournisseur ne fournisse une extension à JDBC et un wrapper pour traiter JDBC avec. Cela dit, il est possible d'envelopper JDBC lui-même avec une file d'attente de traitement, et d'implémenter une logique qui peut traiter hors de la file d'attente sur une ou plusieurs connexions séparées. Un avantage de ceci pour certains types d'appels est que la logique, si sous charge assez lourde, pourrait convertir les appels dans les lots JDBC pour le traitement, ce qui peut accélérer la logique de manière significative. Ceci est très utile pour les appels où des données sont insérées, et le résultat réel n'a besoin d'être enregistré que s'il y a une erreur. Un bon exemple de cela est si les inserts sont effectués pour enregistrer l'activité de l'utilisateur. L'application ne se souciera pas si l'appel se termine immédiatement ou quelques secondes à partir de maintenant.

en guise de note d'accompagnement, un produit sur le marché fournit une approche axée sur les politiques pour permettre les appels asynchrones comme ceux que j'ai décrits comme étant asynchrones ( http://www.heimdalldata.com / ). Avertissement: je suis co-fondateur de cette société. Il permet d'appliquer des expressions régulières aux requêtes de transformation de données telles que insert/update / deletes pour n'importe quelle source de données JDBC, et de les assembler automatiquement pour les traiter. Utilisé avec MySQL et l'option rewriteBatchedStatements ( MySQL et JDBC avec rewriteBatchedStatements=true ), ce qui peut réduire considérablement la charge globale de la base de données.

3
répondu Erik Brandsberg 2017-05-23 11:46:52

on dirait qu'une nouvelle API asynchrone JDBC" JDBC next " est en préparation.

voir présentation ici

vous pouvez télécharger L'API de ici

3
répondu Sebastien 2018-03-19 08:30:44

vous avez trois options à mon avis:

  1. utilisez un file d'attente concurrente pour distribuer des messages à travers un nombre limité et fixe de threads. Donc, si vous avez 1000 connexions de 4 threads, pas 1000 fils.
  2. accédez à la base de données sur un autre noeud (c.-à-d. un autre processus ou une autre machine) et demandez au client de votre base de données de faire des appels asynchrones à ce noeud.
  3. implémenter un véritable système distribué par le biais de messages asynchrones. Pour cela, vous aurez besoin D'une file D'attente de messagerie comme CoralMQ ou Tibco.

Diclaimer: je suis l'un des développeurs de CoralMQ.

2
répondu rdalmeida 2016-02-09 20:25:54

juste une idée folle : vous pourriez utiliser un modèle Iteratee sur jbdc ensemble de résultats enveloppé dans un futur / promesse

Hammersmith n'est que pour les MongoDB .

2
répondu jwinandy 2018-04-24 08:40:36

Je ne pense qu'à des idées. Pourquoi ne pas avoir un pool de connexions de base de données avec chacune ayant un thread. Chaque fil a accès à une file d'attente. Lorsque vous voulez faire une requête qui prend beaucoup de temps, vous pouvez mettre sur la file d'attente, puis l'un des fils va le ramasser et de le gérer. Vous n'aurez jamais trop de fils parce que le nombre de vos fils est limité.

éditer: ou mieux encore, juste un certain nombre de fils. Quand un fil voit quelque chose dans une file d'attente, il demande une connexion à la piscine et s'en occupe.

1
répondu Amir Raminfar 2010-11-03 13:57:04

la bibliothèque commons-dbutils supporte un AsyncQueryRunner auquel vous fournissez un ExecutorService et qui renvoie un Future . Vaut la peine de vérifier car il est simple à utiliser et de s'assurer que vous ne serez pas des ressources de fuite.

1
répondu William Speirs 2011-11-23 01:54:21

voici un aperçu de ce à quoi pourrait ressembler une api jdbc non bloquante d'Oracle présenté à JavaOne: https://static.rainfocus.com/oracle/oow16/sess/1461693351182001EmRq/ppt/CONF1578%2020160916.pdf

il semble donc qu'à la fin, des appels JDBC vraiment asynchrones seront effectivement possibles.

1
répondu nemoo 2017-11-23 09:20:51

si vous êtes intéressé par les API de base de données asynchrones pour Java, vous devez savoir qu'il existe une nouvelle initiative pour venir avec un ensemble d'API standard basé sur CompletableFuture et lambdas. Il y a aussi une implémentation de ces API sur JDBC qui peut être utilisée pour pratiquer ces API: https://github.com/oracle/oracle-db-examples/tree/master/java/AoJ Le JavaDoc est mentionné dans le README du projet github.

0
répondu Jean de Lavarene 2018-04-12 08:07:02

comme mentionné dans d'autres réponses L'API JDBC n'est pas Async par nature.

Cependant, si vous pouvez vivre avec un sous-ensemble des opérations et une API différente, il y a des solutions. Un exemple est https://github.com/jasync-sql/jasync-sql ça marche pour MySQL et PostgreSQL.

0
répondu oshai 2018-09-09 22:04:04

une solution simple consiste à envelopper vos appels jdbs dans CompletableFuture et fournir un pool de threads personnalisé pour ces appels

0
répondu oleffir 2018-10-03 19:26:47