Je me demande s'il existe un moyen de faire des appels asynchrones à une base de données?
Par exemple, imaginez que j'ai une grosse demande qui prend très longtemps à traiter, je veux envoyer la demande et recevoir une notification lorsque la demande renverra une valeur (en passant un écouteur / rappel ou quelque chose). Je ne veux pas bloquer l'attente de la réponse de la base de données.
Je ne considère pas que l'utilisation d'un pool de threads soit une solution car elle ne s'adapte pas, dans le cas de demandes simultanées lourdes, cela engendrera un très grand nombre de threads.
Nous sommes confrontés à ce genre de problème avec les serveurs réseau et nous avons trouvé des solutions en utilisant l'appel système select / poll / epoll pour éviter d'avoir un thread par connexion. Je me demande simplement comment avoir une fonctionnalité similaire avec la demande de base de données?
Remarque: je suis conscient que l'utilisation d'un FixedThreadPool peut être une bonne solution de contournement, mais je suis surpris que personne n'ait développé un système vraiment asynchrone (sans l'utilisation de thread supplémentaire).
** Mise à jour **
Faute de vraies solutions pratiques, j'ai décidé de créer moi - même une librairie (partie de finagle): finagle-mysql . Il décode / décode la requête / réponse mysql et utilise Finagle / Netty sous le capot. Il évolue extrêmement bien même avec un grand nombre de connexions.
la source
Réponses:
Je ne comprends pas comment l'une des approches proposées qui englobent les appels JDBC dans les acteurs, les exécuteurs ou toute autre chose peut aider ici - quelqu'un peut-il clarifier.
Le problème fondamental est certainement que les opérations JDBC se bloquent sur le socket IO. Quand il fait cela, il bloque le fil de discussion à la fin de l'histoire. Quel que soit le cadre d'encapsulation que vous choisissez d'utiliser, un thread sera maintenu occupé / bloqué par requête simultanée.
Si les pilotes de base de données sous-jacents (MySql?) Offrent un moyen d'intercepter la création de socket (voir SocketFactory), alors j'imagine qu'il serait possible de créer une couche de base de données asynchrone pilotée par les événements au-dessus de l'API JDBC, mais nous devrons encapsuler le tout JDBC derrière une façade événementielle, et cette façade ne ressemblerait pas à JDBC (après elle serait événementielle). Le traitement de la base de données se produirait de manière asynchrone sur un thread différent de celui de l'appelant, et vous devrez déterminer comment créer un gestionnaire de transactions qui ne repose pas sur l'affinité des threads.
Quelque chose comme l'approche que je mentionne permettrait même à un seul thread d'arrière-plan de traiter une charge d'exécutions JDBC simultanées. En pratique, vous exécuteriez probablement un pool de threads pour utiliser plusieurs cœurs.
(Bien sûr, je ne fais pas de commentaires sur la logique de la question d'origine, mais uniquement les réponses qui impliquent que la concurrence dans un scénario avec blocage d'E / S de socket est possible sans l'utilisateur d'un modèle de sélecteur - plus simple simplement pour déterminer votre concurrence JDBC typique et mettre dans un pool de connexions de la bonne taille).
On dirait que MySql fait probablement quelque chose du genre que je suggère --- http://code.google.com/p/async-mysql-connector/wiki/UsageExample
la source
Il est impossible de faire un appel asynchrone à la base de données via JDBC, mais vous pouvez faire des appels asynchrones à JDBC avec des acteurs (par exemple, l'acteur appelle la base de données via JDBC et envoie des messages aux tiers, lorsque les appels sont terminés), ou, si vous aimez CPS, avec des futures en pipeline (promesses) (une bonne implémentation est Scalaz Promises )
Les acteurs Scala par défaut sont basés sur les événements (et non sur les threads) - la planification de continuation permet de créer des millions d'acteurs sur une configuration JVM standard.
Si vous ciblez Java, Akka Framework est une implémentation de modèle Actor qui dispose d'une bonne API à la fois pour Java et Scala.
En dehors de cela, la nature synchrone de JDBC me semble parfaitement logique. Le coût d'une session de base de données est bien plus élevé que le coût du thread Java bloqué (en avant ou en arrière-plan) et en attente d'une réponse. Si vos requêtes durent si longtemps que les capacités d'un service d'exécuteur (ou d'encapsulation des frameworks de concurrence Actor / fork-join / promise) ne vous suffisent pas (et que vous consommez trop de threads), vous devez d'abord penser à votre chargement de la base de données. Normalement, la réponse d'une base de données revient très rapidement, et un service exécuteur soutenu avec un pool de threads fixe est une solution suffisante. Si vous avez trop de requêtes de longue durée, vous devriez envisager un (pré-) traitement initial - comme un recalcul nocturne des données ou quelque chose comme ça.
la source
Peut-être pourriez-vous utiliser un système de messagerie asynchrone JMS, qui évolue assez bien, à mon humble avis:
Envoyez un message à une file d'attente, où les abonnés accepteront le message et exécuteront le processus SQL. Votre processus principal continuera de fonctionner et d'accepter ou d'envoyer de nouvelles demandes.
Lorsque le processus SQL se termine, vous pouvez exécuter la méthode inverse: envoyer un message à ResponseQueue avec le résultat du processus, et un écouteur côté client l'accepte et exécute le code de rappel.
la source
Il n'y a pas de support direct dans JDBC mais vous avez plusieurs options comme MDB, Executors from Java 5.
"Je ne considère pas que l'utilisation d'un pool de threads soit une solution car elle ne s'adapte pas, dans le cas de requêtes simultanées lourdes, cela engendrera un très grand nombre de threads."
Je suis curieux de savoir pourquoi un pool limité de threads ne va pas à l'échelle? Il s'agit d'un pool et non d'un thread par requête pour générer un thread pour chaque requête. J'utilise cela depuis un certain temps sur une application Web à forte charge et nous n'avons vu aucun problème jusqu'à présent.
la source
Il semble qu'une nouvelle API jdbc asynchrone "JDBC next" soit en préparation.
Voir la présentation ici
Vous pouvez télécharger l'API ici
la source
Comme mentionné dans d'autres réponses, l'API JDBC n'est pas Async de par sa nature.
Cependant, si vous pouvez vivre avec un sous-ensemble des opérations et une API différente, il existe des solutions. Un exemple est https://github.com/jasync-sql/jasync-sql qui fonctionne pour MySQL et PostgreSQL.
la source
Le projet Ajdbc semble répondre à ce problème http://code.google.com/p/adbcj/
Il existe actuellement 2 pilotes expérimentaux nativement asynchrones pour mysql et postgresql.
la source
Une vieille question, mais quelques informations supplémentaires. Il n'est pas possible que JDBC émette des requêtes asynchrones vers la base de données elle-même, à moins qu'un fournisseur ne fournisse une extension à JDBC et un wrapper pour gérer JDBC. Cela dit, il est possible d'encapsuler JDBC lui-même avec une file d'attente de traitement et d'implémenter une logique permettant de 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 elle est soumise à une charge suffisamment élevée, pourrait convertir les appels en lots JDBC pour le traitement, ce qui peut accélérer considérablement la logique. Ceci est très utile pour les appels où des données sont insérées, et le résultat réel ne doit être consigné qu'en cas d'erreur. Un bon exemple de ceci est si des insertions sont effectuées pour enregistrer l'activité de l'utilisateur. L'application a gagné '
En remarque, un produit sur le marché offre une approche politique pour permettre aux appels asynchrones comme ceux que j'ai décrits d'être effectués de manière asynchrone ( http://www.heimdalldata.com/ ). Avertissement: Je suis co-fondateur de cette société. Il permet d'appliquer des expressions régulières aux demandes de transformation de données telles que l'insertion / la mise à jour / la suppression de toute source de données JDBC, et les regroupera automatiquement pour le traitement. Lorsqu'il est utilisé avec MySQL et l'option rewriteBatchedStatements ( MySQL et JDBC avec rewriteBatchedStatements = true ), cela peut réduire considérablement la charge globale de la base de données.
la source
Vous avez trois options à mon avis:
Diclaimer: Je suis l'un des développeurs de CoralMQ.
la source
Une solution est en cours de développement pour rendre possible la connectivité réactive avec des bases de données relationnelles standard.
Site Web de R2DBC
GitHub de R2DBC
Matrice des fonctionnalités
la source
Les exécuteurs Java 5.0 peuvent être utiles.
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 utiliserCallable
, qui renvoie un résultat. Le résultat est encapsulé dans unFuture<ReturnType>
objet, vous pouvez donc l'obtenir à son retour.la source
Voici un aperçu de ce à quoi pourrait ressembler une API jdbc non bloquante d'Oracle présentée à JavaOne: https://static.rainfocus.com/oracle/oow16/sess/1461693351182001EmRq/ppt/CONF1578%2020160916.pdf
Il semble donc qu'à la fin, des appels JDBC véritablement asynchrones seront effectivement possibles.
la source
Juste une idée folle: vous pouvez utiliser un modèle Iteratee sur JBDC resultSet enveloppé dans un Future / Promise
Hammersmith fait cela pour MongoDB .
la source
Je pense juste à des idées ici. Pourquoi ne pouviez-vous pas avoir un pool de connexions de base de données avec chacune un thread. Chaque thread a accès à une file d'attente. Lorsque vous souhaitez effectuer une requête qui prend beaucoup de temps, vous pouvez la mettre dans la file d'attente, puis l'un des threads la récupérera et la traitera. Vous n'aurez jamais trop de threads car le nombre de vos threads est limité.
Edit: Ou mieux encore, juste un certain nombre de fils. Lorsqu'un thread voit quelque chose dans une file d'attente, il demande une connexion à partir du pool et le gère.
la source
La bibliothèque commons-dbutils prend en charge un pour
AsyncQueryRunner
lequel vous fournissez unExecutorService
to et renvoie un fichierFuture
. Vaut le détour car il est simple à utiliser et vous assure de ne pas perdre de ressources.la source
Si vous êtes intéressé par les API de base de données asynchrones pour Java, sachez qu'il existe une nouvelle initiative visant à proposer un ensemble d'API standard basées sur CompletableFuture et lambdas. Il existe également 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 de le projet github.
la source