web-dev-qa-db-fra.com

Quelle est la meilleure solution pour le regroupement de connexions de bases de données en python?

J'ai développé des classes personnalisées de type DAO afin de répondre à des exigences très spécifiques de mon projet. Il s'agit d'un processus côté serveur qui ne s'exécute dans aucun type de cadre. 

La solution fonctionne très bien sauf que chaque fois qu'une nouvelle requête est faite, j'ouvre une nouvelle connexion via MySQLdb.connect. 

Quelle est la meilleure solution "directe" pour passer de l’utilisation du pool de connexions en python? J'imagine quelque chose comme la solution commune DBCP pour Java. 

Le processus est long et a beaucoup de threads qui doivent faire des demandes, mais pas tous en même temps ... en particulier ils font beaucoup de travail avant l'éclatement d'une petite partie de leurs résultats.

Édité pour ajouter: Après quelques recherches supplémentaires, j'ai trouvé anitpool.py qui a l'air décent, mais comme je suis relativement nouveau en python, je suppose que je veux juste m'assurer que je ne manque pas de plus évident/plus idiomatique/meilleure solution. 

31
John

OMI, la "solution la plus évidente/la plus idiomatique/la meilleure" consiste à utiliser un ORM existant plutôt que d'inventer des classes de type DAO.

Il me semble que les ORM sont plus populaires que les connexions SQL "brutes". Pourquoi? Parce que Python est OO, et le mappage de la ligne SQL sur l’objet est absolument essentiel. Il n'y a pas beaucoup de cas où vous traitez avec des lignes SQL qui ne correspondent pas à des objets Python.

Je pense que (SQLAlchemy } _ ou SQLObject (et le pooling de connexions associé) est la solution Pythonic la plus idiomatique.

Le regroupement en tant que fonctionnalité distincte n'est pas très courant, car le SQL pur (sans mappage d'objet) n'est pas très utilisé pour le type de processus complexes à exécution longue qui bénéficient du regroupement de connexions. Oui, le SQL pur est utilisé, mais il est toujours utilisé dans des applications plus simples ou plus contrôlées où la mise en pool n'est pas utile.

Je pense que vous pourriez avoir deux alternatives:

  1. Révisez vos classes pour utiliser SQLAlchemy ou SQLObject. Bien que cela semble douloureux au début [tout ce travail gaspillé], vous devriez être en mesure de tirer parti de toute la conception et de la pensée. Il ne s’agit que d’un exercice consistant à adopter une solution de gestion des ressources et de mutualisation largement utilisée.
  2. Lancez votre propre pool de connexions simples en utilisant l'algorithme que vous avez décrit - un simple ensemble ou une liste de connexions que vous parcourez. 
16
S.Lott

En MySQL?

Je dirais ne vous embêtez pas avec la mise en commun des connexions. Ils sont souvent une source de problèmes et avec MySQL, ils ne vous apporteront pas l’avantage de performances que vous espériez. Cette voie peut faire l’objet de beaucoup d’efforts - politiquement - car il ya tellement de bonnes pratiques en matière de pratique de la main courante et de verbiage de manuels scolaires sur les avantages de la mise en commun des connexions.

Les pools de connexions constituent simplement un pont entre l'ère post-Web des applications sans état (par exemple, le protocole HTTP) et l'ère pré-Web des applications de traitement par lots longue durée avec état. Étant donné que les connexions dans les bases de données pré-Web étaient très coûteuses (personne ne se souciant trop du temps qu’il fallait pour établir une connexion), les applications post-Web ont conçu ce schéma de pool de connexions de manière à ce que chaque hit n’entraîne pas cette surcharge de traitement. sur le SGBDR.

Étant donné que MySQL est davantage un SGBDR d’époque Web, les connexions sont extrêmement légères et rapides. J'ai écrit de nombreuses applications Web à volume élevé qui n'utilisent pas du tout un pool de connexions pour MySQL.

C’est une complication dont vous pouvez tirer parti, s’il n’ya pas d’obstacle politique à surmonter.

22
mbac32768

Enveloppez votre classe de connexion.

Fixez une limite au nombre de connexions que vous établissez . Renvoyez une connexion inutilisée . Interceptez près pour libérer la connexion.

Mise à jour: J'ai mis quelque chose comme ceci dans dbpool.py:

import sqlalchemy.pool as pool
import MySQLdb as mysql
mysql = pool.manage(mysql)
16
Chris

Vieux thread, mais pour le pooling à usage général (connexions ou tout objet coûteux), j'utilise quelque chose comme:

def pool(ctor, limit=None):
    local_pool = multiprocessing.Queue()
    n = multiprocesing.Value('i', 0)
    @contextlib.contextmanager
    def pooled(ctor=ctor, lpool=local_pool, n=n):
        # block iff at limit
        try: i = lpool.get(limit and n.value >= limit)
        except multiprocessing.queues.Empty:
            n.value += 1
            i = ctor()
        yield i
        lpool.put(i)
    return pooled

Ce qui construit paresseusement, a une limite optionnelle et devrait être généralisé à tous les cas d’utilisation auxquels je peux penser. Bien entendu, cela suppose que vous ayez vraiment besoin de la mise en pool de toutes les ressources, ce qui n'est pas le cas pour de nombreux SQL-like modernes. Usage:

# in main:
my_pool = pool(lambda: do_something())
# in thread:
with my_pool() as my_obj:
    my_obj.do_something()

Cela suppose que tout ce que l'objet créé par ctor possède un destructeur approprié si nécessaire (certains serveurs ne détruisent pas les objets de connexion à moins qu'ils ne soient fermés explicitement).

6
metaperture

Je viens de chercher le même genre de chose.

J'ai trouvé pysqlpool et le module de pool sqlalchemy

2
Willie

Créer votre propre pool de connexion est une mauvaise idée si votre application décide de commencer à utiliser le multi-threading. La création d'un pool de connexions pour une application multithread est beaucoup plus compliquée que celle d'une application mono-thread. Vous pouvez utiliser quelque chose comme PySQLPool dans ce cas.

C'est aussi une mauvaise idée d'utiliser un ORM si vous recherchez de la performance.

Si vous traitez avec des bases de données énormes/lourdes qui doivent gérer un grand nombre de sélections, d'insertions, de mises à jour Et de suppressions en même temps, vous aurez besoin de performances, ce qui signifie que vous aurez besoin d'une écriture SQL personnalisée pour optimiser les recherches et les temps de verrouillage. Avec un ORM, vous n’avez généralement pas cette souplesse.

Donc, en gros, vous pouvez créer votre propre pool de connexion et utiliser des ORM, mais uniquement si vous êtes certain de ne pas avoir besoin de ce que je viens de décrire.

2
flexo

En répondant à un ancien fil de discussion mais la dernière fois que j'ai vérifié, MySQL propose le regroupement de connexions dans le cadre de ses pilotes.

Vous pouvez les vérifier à:

https://dev.mysql.com/doc/connector-python/en/connector-python-connection-pool.html

À partir de TFA, supposons que vous souhaitiez ouvrir un pool de connexions explicitement (comme OP l’avait indiqué):

dbconfig = {  "database": "test", "user":"joe" }
cnxpool = mysql.connector.pooling.MySQLConnectionPool(pool_name = "mypool",pool_size = 3, **dbconfig)

On accède ensuite à ce pool en effectuant une demande auprès du pool via la fonction get_connection ().

cnx1 = cnxpool.get_connection()
cnx2 = cnxpool.get_connection()
1
kilokahn

Utilisez DBUtils, simple et fiable.

pip install DBUtils

0
ospider