La bibliothèque DBUtils fournit une abstraction solide pour orchestrer la durée de vie et la mutualisation des sessions bases de données au sein d'applications Python multitâches. Son architecture repose sur deux stratégies complémentaires adoptées à des modèles de concurrence différents.
Stratégie PersistentDB
Ce mode alloue un canal unique et persistant par thread en cours d'exécution. Même lorsqu'une instruction .close() est invoquée, la liaison réseau n'est pas physiquement interrompue ; elle est simplement relâchée vers le cache local du fil actif. La déconnexion finale n'a lieu qu'à l'arrêt naturel du thread, garantissant une latence réduite lors des appels successifs depuis le même contexte.
import pymysql
from DBUtils.PersistentDB import PersistentDB
PARAMÈTRES_CONNEXION = {
"host": "127.0.0.1",
"port": 3306,
"user": "administrateur",
"passwd": "mot_de_passe_sécurisé",
"db": "catalogue_produit",
"charset": "utf8mb4",
"autocommit": True
}
# Installation du gardien de sessions thread-locales
gestionnaire_persistant = PersistentDB(
creator=pymysql,
ping=1, # Sondage d'intégrité avant chaque transaction
closeable=False, # Empêche la fermeture socket réelle
maxusage=None, # Autorise une réutilisation infinie
setsession=["SET SESSION wait_timeout=28800"]
)
def obtenir_données_récentes():
# Récupération d'un pont réservé exclusivement au thread actuel
liaison = gestionnaire_persistant.connection()
exécuteur = liaison.cursor(pymysql.cursors.DictCursor)
try:
exécuteur.execute(
"SELECT identifiant, intitulé FROM articles WHERE date_publi > %s",
("2023-01-01",)
)
return exécuteur.fetchall()
finally:
if liaison: liaison.close() # Retour dans le buffer thread-local
if __name__ == "__main__":
print(obtenir_données_récentes())
Stratégie PooledDB
L'approche mutualisée initialise un groupe de liaisons prédéfini au lanccement de l'application. Les requêtes concurrentes y puisent des références disponibles. Dès qu'un traitement se termine, la session est renvoyée dans la file d'attente (idle queue) plutôt que détruite. Ce modèle nécessite de gérer des indicateurs de saturation pour éviter la surcharge du serveur distant.
import pymysql
from DBUtils.PooledDB import PooledDB
CONFIG_POOL = {
"maxconnections": 12, # Plafond absolu d'instanciations
"mincached": 4, # Canaux créés dès le démarrage
"maxcached": 6, # Limite du cache de sessions inactives
"blocking": True, # Mise en attente si le réservoir est vide
"ping": 1, # Vérification de connectivité implicite
"creator": pymysql,
"host": "127.0.0.1",
"port": 3306,
"user": "lecteur_seul",
"passwd": "lecture_seule_123",
"database": "analytics",
"charset": "utf8mb4"
}
# Construction du bassin collectif
bassin_partagé = PooledDB(**CONFIG_POOL)
def consulter_indicateurs():
# Allocation synchrone d'un handle libre ou suspension jusqu'à libération
passage = bassin_partagé.connection()
processeur = passage.cursor()
try:
processeur.execute("SELECT SUM(valeur_brute) FROM mesures WHERE type=%s", ("température",))
résultat = processeur.fetchone()[0]
return résultat if résultat else 0.0
except pymysql.DatabaseError as e:
print(f"Interruption requête: {e}")
return None
finally:
passage.close() # Restauration dans le pool global
if __name__ == "__main__":
print(contreler_indicateurs())
Paramétrage Technique Détaillé
- creator : Spécifie le driver MySQL/MariaDB à injecter dans la factory de connexions.
- maxconnections / mincached / maxcached : Définit respectivement le plafond légal, l'amorçage initial et la capacité maximale du cache inactif. Un dépassement déclenche soit un blocage (
blocking=True), soit une exceptionTooManyConnections. - ping : Contrôles périodiques envoyés au daemon SQL. Une valeur
1active la vérification systématique avant utilisation, améliorant la résilience face aux coupures réseau silencieuses. - setsession : Liste de directives DDL/DML exécutées automatiquement lors de l'obtention d'une nouvelle liaison (paramètres locaux, fuseaux horaires, modes SQL).
- Note d'implémentation PyMySQL : Le pilote natif expose une propriété thread-safety fixée à
1. Cela implique que les objets connexion ne peuvent être partagés efficacement entre fils simultanément. Le moteur interne réconcilie cela en assignant des wrappers dédiés tout en maintenant une base physique commune, rendant souvent le paramètremaxsharedredondant dans les stacks modernes.