| [ Web Proxy ] |
| Viewing: https://raw.githubusercontent.com/WebwareForPython/DBUtils/main/docs/main.de.html | [Back] [Original] |
English | German
Inhalt
DBUtils ist eine Sammlung von Python-Modulen, mit deren Hilfe man in Python geschriebene Multithread-Anwendungen auf sichere und effiziente Weise an Datenbanken anbinden kann.
DBUtils wurde ursprnglich speziell fr Webware for Python als Anwendung und PyGreSQL als PostgreSQL-Datenbankadapter entwickelt, kann aber inzwischen fr beliebige Python-Anwendungen und beliebige auf DB-API 2 beruhende Python-Datenbankadapter verwendet werden.
DBUtils ist als Python-Package realisiert worden, das aus zwei verschiedenen Gruppen von Modulen besteht: Einer Gruppe zur Verwendung mit beliebigen DB-API-2-Datenbankadaptern, und einer Gruppe zur Verwendung mit dem klassischen PyGreSQL-Datenbankadapter-Modul.
Allgemeine Variante fr beliebige DB-API-2-Adapter |
|
|---|---|
steady_db |
Gehrtete DB-API-2-Datenbankverbindungen |
pooled_db |
Pooling fr DB-API-2-Datenbankverbindungen |
persistent_db |
Persistente DB-API-2-Datenbankverbindungen |
simple_pooled_db |
Einfaches Pooling fr DB-API 2 |
Variante speziell fr den klassischen PyGreSQL-Adapter |
|
|---|---|
steady_pg |
Gehrtete klassische PyGreSQL-Verbindungen |
pooled_pg |
Pooling fr klassische PyGreSQL-Verbindungen |
persistent_pg |
Persistente klassische PyGreSQL-Verbindungen |
simple_pooled_pg |
Einfaches Pooling fr klassisches PyGreSQL |
Die Abhngigkeiten der Module in der Variante fr beliebige DB-API-2-Adapter sind im folgenden Diagramm dargestellt:
[dependencies_db.png]
Die Abhngigkeiten der Module in der Variante fr den klassischen PyGreSQL-Adapter sehen hnlich aus:
[dependencies_pg.png]
Die aktuelle Version von DBUtils kann vom Python Package Index heruntergeladen werden:
https://pypi.python.org/pypi/DBUtils
Das Source-Code-Repository befindet sich hier auf GitHub:
https://github.com/WebwareForPython/DBUtils
Das Paket kann auf die bliche Weise installiert werden:
python setup.py install
Noch einfacher ist, das Paket in einem Schritt mit pip automatisch herunterzuladen und zu installieren:
pip install DBUtils
DBUtils untersttzt die Python Versionen 3.7 bis 3.14.
Die Module in der Variante fr klassisches PyGreSQL bentigen PyGreSQL Version 4.0 oder hher, whrend die Module in der allgemeinen Variante fr DB-API 2 mit jedem beliebigen Python-Datenbankadapter-Modul zusammenarbeiten, das auf DB-API 2 basiert.
Dieser Abschnitt verwendet nur die Bezeichnungen der DB-API-2-Variante, aber Entsprechendes gilt auch fr die PyGreSQL-Variante.
DBUtils installiert sich als Paket dbutils, das alle hier beschriebenen Module enthlt. Jedes dieser Module enthlt im Wesentlichen eine Klasse, die einen analogen Namen trgt und die jeweilige Funktionalitt bereitstellt. So enthlt z.B. das Modul dbutils.pooled_db die Klasse PooledDB.
Die Klasse SimplePooledDB in dbutils.simple_pooled_db ist eine sehr elementare Referenz-Implementierung eines Pools von Datenbankverbindungen. Hiermit ist ein Vorratsspeicher an Datenbankverbindungen gemeint, aus dem sich die Python-Anwendung bedienen kann. Diese Implementierung ist weit weniger ausgefeilt als das eigentliche pooled_db-Modul und stellt insbesondere keine Ausfallsicherung zur Verfgung. dbutils.simple_pooled_db ist im Wesentlichen identisch mit dem zu Webware for Python gehrenden Modul MiscUtils.DBPool. Es ist eher zur Verdeutlichung des Konzepts gedacht, als zum Einsatz im produktiven Betrieb.
Die Klasse SteadyDBConnection im Modul dbutils.steady_db stellt "gehrtete" Datenbankverbindungen bereit, denen gewhnliche Verbindungen eines DB-API-2-Datenbankadapters zugrunde liegen. Eine "gehrtete" Verbindung wird bei Zugriff automatisch, ohne dass die Anwendung dies bemerkt, wieder geffnet, wenn sie geschlossen wurde, die Datenbankverbindung unterbrochen wurde, oder wenn sie fter als ein optionales Limit genutzt wurde.
Ein typisches Beispiel, wo dies bentigt wird, ist, wenn die Datenbank neu gestartet wurde, whrend Ihre Anwendung immer noch luft und Verbindungen zur Datenbank offen hat, oder wenn Ihre Anwendung auf eine entfernte Datenbank ber ein Netzwerk zugreift, das durch eine Firewall geschtzt ist, und die Firewall neu gestartet wurde und dabei ihren Verbindungsstatus verloren hat.
Normalerweise benutzen Sie das steady_db-Modul nicht direkt; es wird aber von den beiden nchsten Modulen bentigt, persistent_db und pooled_db.
Die Klasse PersistentDB im Modul dbutils.persistent_db stellt gehrtete, thread-affine, persistente Datenbankverbindungen zur Verfgung, unter Benutzung eines beliebigen DB-API-2-Datenbankadapters. Mit "thread-affin" und "persistent" ist hierbei gemeint, dass die einzelnen Datenbankverbindungen den jeweiligen Threads fest zugeordnet bleiben und whrend der Laufzeit des Threads nicht geschlossen werden.
Das folgende Diagramm zeigt die beteiligten Verbindungsschichten, wenn Sie persistent_db-Datenbankverbindungen einsetzen:
[persistent.png]
Immer wenn ein Thread eine Datenbankverbindung zum ersten Mal ffnet, wird eine neue Datenbankverbindung geffnet, die von da an immer wieder fr genau diesen Thread verwendet wird. Wenn der Thread die Datenbankverbindung schliet, wird sie trotzdem weiter offen gehalten, damit beim nchsten Mal, wenn der gleiche Thread wieder eine Datenbankverbindung anfordert, diese gleiche bereits geffnete Datenbankverbindung wieder verwendet werden kann. Die Verbindung wird automatisch geschlossen, wenn der Thread beendet wird.
Kurz gesagt versucht persistent_db Datenbankverbindungen wiederzuverwerten, um die Gesamteffizienz der Datenbankzugriffe Ihrer Multithread-Anwendungen zu steigern, aber es wird dabei sichergestellt, dass verschiedene Threads niemals die gleiche Verbindung benutzen.
Daher arbeitet persistent_db sogar dann problemlos, wenn der zugrunde liegende DB-API-2-Datenbankadapter nicht thread-sicher auf der Verbindungsebene ist, oder wenn parallele Threads Parameter der Datenbank-Sitzung verndern oder Transaktionen mit mehreren SQL-Befehlen durchfhren.
Die Klasse PooledDB im Modul dbutils.pooled_db stellt, unter Benutzung eines beliebigen DB-API-2-Datenbankadapters, einen Pool von gehrteten, thread-sicheren Datenbankverbindungen zur Verfgung, die automatisch, ohne dass die Anwendung dies bemerkt, wiederverwendet werden.
Das folgende Diagramm zeigt die beteiligten Verbindungsschichten, wenn Sie pooled_db-Datenbankverbindungen einsetzen:
[pooled.png]
Wie im Diagramm angedeutet, kann pooled_db geffnete Datenbankverbindungen den verschiedenen Threads beliebig zuteilen. Dies geschieht standardmig, wenn Sie den Verbindungspool mit einem positiven Wert fr maxshared einrichten und der zugrunde liegende DB-API-2-Datenbankadapter auf der Verbindungsebene thread-sicher ist, aber Sie knnen auch dedizierte Datenbankverbindungen anfordern, die nicht von anderen Threads verwendet werden sollen. Neben dem Pool gemeinsam genutzter Datenbankverbindungen ("shared pool") knnen Sie auch einen Pool von mindestens mincached und hchstens maxcached inaktiven Verbindungen auf Vorrat einrichten ("idle pool"), aus dem immer dann geschpft wird, wenn ein Thread eine dedizierte Datenbankverbindung anfordert, oder wenn der Pool gemeinsam genutzter Datenbankverbindungen noch nicht voll ist. Wenn ein Thread eine Datenbankverbindung schliet, die auch von keinem anderen Thread mehr benutzt wird, wird sie an den Vorratsspeicher inaktiver Datenbankverbindungen zurckgegeben, damit sie wiederverwertet werden kann.
Wenn der zugrunde liegende DB-API-Datenbankadapter nicht thread-sicher ist, werden Thread-Locks verwendet, um sicherzustellen, dass die pooled_db-Verbindungen dennoch thread-sicher sind. Sie brauchen sich also hierum keine Sorgen zu machen, aber Sie sollten darauf achten, dedizierte Datenbankverbindungen zu verwenden, sobald Sie Parameter der Datenbanksitzung verndern oder Transaktionen mit mehreren SQL-Befehlen ausfhren.
Sowohl persistent_db als auch pooled_db dienen dem gleichen Zweck, nmlich die Effizienz des Datenbankzugriffs durch Wiederverwendung von Datenbankverbindungen zu steigern, und dabei gleichzeitig die Stabilitt zu gewhrleisten, selbst wenn die Datenbankverbindung unterbrochen wird.
Welches der beiden Module sollte also verwendet werden? Nach den obigen Erklrungen ist es klar, dass persistent_db dann sinnvoller ist, wenn Ihre Anwendung eine gleich bleibende Anzahl Threads verwendet, die hufig auf die Datenbank zugreifen. In diesem Fall werden Sie ungefhr die gleiche Anzahl geffneter Datenbankverbindungen erhalten. Wenn jedoch Ihre Anwendung hufig Threads beendet und neu startet, dann ist pooled_db die bessere Lsung, die auch mehr Mglichkeiten zur Feineinstellung zur Verbesserung der Effizienz erlaubt, insbesondere bei Verwendung eines thread-sicheren DB-API-2-Datenbankadapters.
Da die Schnittstellen beider Module sehr hnlich sind, knnen Sie recht einfach von einem Modul zum anderen wechseln und austesten, welches geeigneter ist.
Die Benutzung aller Module ist zwar recht hnlich, aber es gibt vor allem bei der Initialisierung auch einige Unterschiede, sowohl zwischen den "Pooled"- und den "Persistent"-Varianten, als auch zwischen den DB-API-2- und den PyGreSQL-Varianten.
Wir werden hier nur auf das persistent_db-Modul und das etwas kompliziertere pooled_db-Modul eingehen. Einzelheiten zu den anderen Modulen finden Sie in deren Docstrings. Unter Verwendung der Python-Interpreter-Konsole knnen Sie sich die Dokumentation des pooled_db-Moduls wie folgt anzeigen lassen (dies funktioniert entsprechend auch mit den anderen Modulen):
help(pooled_db)
Wenn Sie das persistent_db-Modul einsetzen mchten, mssen Sie zuerst einen Generator fr die von Ihnen gewnschte Art von Datenbankverbindungen einrichten, indem Sie eine Instanz der Klasse PersistentDB erzeugen, wobei Sie folgende Parameter angeben mssen:
creator: entweder eine Funktion, die neue DB-API-2-Verbindungen erzeugt, oder ein DB-API-2-Datenbankadapter-Modul
maxusage: Obergrenze dafr, wie oft eine einzelne Verbindung wiederverwendet werden darf (der Standardwert 0 oder None bedeutet unbegrenzte Wiederverwendung)
Sobald diese Obergrenze erreicht wird, wird die Verbindung zurckgesetzt.
setsession: eine optionale Liste von SQL-Befehlen zur Initialisierung der Datenbanksitzung, z.B. ["set datestyle to german", ...]
failures: eine optionale Exception-Klasse oder ein Tupel von Exceptions, bei denen die Ausfallsicherung zum Tragen kommen soll, falls die Vorgabe (OperationalError, InterfaceError, InternalError) fr das verwendete Datenbankadapter-Modul nicht geeignet sein sollte
isfatal: eine optionale Funktion, der die aufgetretene Exception bergeben wird und die zurckgibt, ob die Ausfallsicherung zum Tragen kommen soll (muss als Schlsselwort-Argument bergeben werden, siehe Steuerung der Ausfallsicherung)
ping: mit diesem Parameter kann eingestellt werden, wann Verbindungen geprft werden (0 = None = nie, 1 = Standardwert = immer wenn neu angefragt, 2 = vor Erzeugen eines Cursors, 4 = vor dem Ausfhren von Abfragen, 7 = immer, und alle Bitkombinationen dieser Werte)
Standardmig werden Verbindungen mit der ping()-Methode geprft, falls eine solche vorhanden ist. Sie knnen fr die Prfung stattdessen auch einen SQL-Befehl oder eine Funktion angeben, die dann wie bei ping=1 erfolgt, oder ein Tupel aus dem obigen Wert und einem der beiden (siehe Prfung der Verbindungen).
closeable: wenn dies auf True gesetzt wird, dann wird das Schlieen von Verbindungen erlaubt, normalerweise wird es jedoch ignoriert
threadlocal: eine optionale Klasse zur Speicherung thread-lokaler Daten, die anstelle unserer Python-Implementierung benutzt wird (threading.local ist schneller, kann aber nicht in allen Fllen verwendet werden)
Die als creator angegebene Funktion oder die Funktion connect des DB-API-2-Datenbankadapter-Moduls erhalten alle weiteren Parameter, wie host, database, user, password usw. Sie knnen einige oder alle dieser Parameter in Ihrer eigenen creator-Funktion setzen, was ausgefeilte Mechanismen zur Ausfallsicherung und Lastverteilung ermglicht.
Wenn Sie beispielsweise pgdb als DB-API-2-Datenbankadapter verwenden, und mchten, dass jede Verbindung Ihrer lokalen Datenbank meinedb 1000 mal wiederverwendet werden soll, sieht die Initialisierung so aus:
import pgdb # importiere das verwendete DB-API-2-Modul from dbutils.persistent_db import PersistentDB persist = PersistentDB(pgdb, 1000, database='meinedb')
Nachdem Sie den Generator mit diesen Parametern eingerichtet haben, knnen Sie derartige Datenbankverbindungen von da an wie folgt anfordern:
db = persist.connection()
Sie knnen diese Verbindungen verwenden, als wren sie gewhnliche DB-API-2-Datenbankverbindungen. Genauer genommen erhalten Sie die "gehrtete" steady_db-Version der zugrunde liegenden DB-API-2-Verbindung.
Wenn Sie eine solche persistente Verbindung mit db.close() schlieen, wird dies stillschweigend ignoriert, denn sie wrde beim nchsten Zugriff sowieso wieder geffnet, und das wre nicht im Sinne persistenter Verbindungen. Stattdessen wird die Verbindung automatisch dann geschlossen, wenn der Thread endet. Sie knnen dieses Verhalten ndern, indem Sie den Parameter namens closeable setzen.
Warnung
Bitte beachten Sie, dass Transaktionen explizit durch Aufruf der Methode begin() eingeleitet werden mssen. Hierdurch wird sichergestellt, dass das transparente Neuerffnen von Verbindungen bis zum Ende der Transaktion ausgesetzt wird, und dass die Verbindung zurckgerollt wird, bevor sie vom gleichen Thread erneut benutzt wird.
Das Holen einer Verbindung kann etwas beschleunigt werden, indem man den Parameter threadlocal auf threading.local setzt; dies knnte aber in einigen Umgebungen nicht funktionieren (es ist zum Beispiel bekannt, dass mod_wsgi hier Probleme bereitet, da es Daten, die mit threading.local gespeichert wurden, zwischen Requests lscht).
Wenn Sie das pooled_db-Modul einsetzen mchten, mssen Sie zuerst einen Pool fr die von Ihnen gewnschte Art von Datenbankverbindungen einrichten, indem Sie eine Instanz der Klasse PooledDB erzeugen, wobei Sie folgende Parameter angeben mssen:
creator: entweder eine Funktion, die neue DB-API-2-Verbindungen erzeugt, oder ein DB-API-2-Datenbankadapter-Modul
mincached: die anfngliche Anzahl inaktiver Verbindungen, die auf Vorrat gehalten werden sollen (der Standardwert 0 bedeutet, dass beim Start keine Verbindungen geffnet werden)
maxcached: Obergrenze fr die Anzahl inaktiver Verbindungen, die auf Vorrat gehalten werden sollen (der Standardwert 0 oder None bedeutet unbegrenzte Gre des Vorratsspeichers)
maxshared: Obergrenze fr die Anzahl gemeinsam genutzter Verbindungen (der Standardwert 0 oder None bedeutet, dass alle Verbindungen dediziert sind)
Wenn diese Obergrenze erreicht wird, werden Verbindungen gemeinsam genutzt, sofern diese als gemeinsam nutzbar angefordert werden.
maxconnections: Obergrenze fr die Anzahl an Datenbankverbindungen, die insgesamt berhaupt erlaubt werden sollen (der Standardwert 0 oder None bedeutet unbegrenzte Anzahl von Datenbankverbindungen)
blocking: bestimmt das Verhalten bei berschreitung dieser Obergrenze
Wenn dies auf True gesetzt wird, dann wird so lange gewartet, bis die Anzahl an Datenbankverbindungen wieder abnimmt, normalerweise wird jedoch sofort eine Fehlermeldung ausgegeben.
maxusage: Obergrenze dafr, wie oft eine einzelne Verbindung wiederverwendet werden darf (der Standardwert 0 oder None bedeutet unbegrenzte Wiederverwendung)
Sobald diese Obergrenze erreicht wird, wird die Verbindung automatisch zurckgesetzt (geschlossen und wieder neu geffnet).
setsession: eine optionale Liste von SQL-Befehlen zur Initialisierung der Datenbanksitzung, z.B. ["set datestyle to german", ...]
reset: wie Verbindungen zurckgesetzt werden sollen, bevor sie wieder in den Verbindungspool zurckgegeben werden (False oder None um mit begin() gestartete Transaktionen zurckzurollen, der Standardwert True rollt sicherheitshalber mgliche Transaktionen immer zurck)
failures: eine optionale Exception-Klasse oder ein Tupel von Exceptions, bei denen die Ausfallsicherung zum Tragen kommen soll, falls die Vorgabe (OperationalError, InterfaceError, InternalError) fr das verwendete Datenbankadapter-Modul nicht geeignet sein sollte
isfatal: eine optionale Funktion, der die aufgetretene Exception bergeben wird und die zurckgibt, ob die Ausfallsicherung zum Tragen kommen soll (muss als Schlsselwort-Argument bergeben werden, siehe Steuerung der Ausfallsicherung)
ping: mit diesem Parameter kann eingestellt werden, wann Verbindungen geprft werden (0 = None = nie, 1 = Standardwert = immer wenn neu angefragt, 2 = vor Erzeugen eines Cursors, 4 = vor dem Ausfhren von Abfragen, 7 = immer, und alle Bitkombinationen dieser Werte)
Standardmig werden Verbindungen mit der ping()-Methode geprft, falls eine solche vorhanden ist. Sie knnen fr die Prfung stattdessen auch einen SQL-Befehl oder eine Funktion angeben, die dann wie bei ping=1 erfolgt, oder ein Tupel aus dem obigen Wert und einem der beiden (siehe Prfung der Verbindungen).
Die als creator angegebene Funktion oder die Funktion connect des DB-API-2-Datenbankadapter-Moduls erhalten alle weiteren Parameter, wie host, database, user, password usw. Sie knnen einige oder alle dieser Parameter in Ihrer eigenen creator-Funktion setzen, was ausgefeilte Mechanismen zur Ausfallsicherung und Lastverteilung ermglicht.
Wenn Sie beispielsweise pgdb als DB-API-2-Datenbankadapter benutzen, und einen Pool von mindestens fnf Datenbankverbindungen zu Ihrer Datenbank meinedb verwenden mchten, dann sieht die Initialisierung so aus:
import pgdb # importiere das verwendete DB-API-2-Modul from dbutils.pooled_db import PooledDB pool = PooledDB(pgdb, 5, database='meinedb')
Nachdem Sie den Pool fr Datenbankverbindungen so eingerichtet haben, knnen Sie Verbindungen daraus wie folgt anfordern:
db = pool.connection()
Sie knnen diese Verbindungen verwenden, als wren sie gewhnliche DB-API-2-Datenbankverbindungen. Genauer genommen erhalten Sie die "gehrtete" steady_db-Version der zugrunde liegenden DB-API-2-Verbindung.
Bitte beachten Sie, dass die Verbindung von anderen Threads mitgenutzt werden kann, wenn Sie den Parameter maxshared auf einen Wert grer als Null gesetzt haben, und der zugrunde liegende DB-API-2-Datenbankadapter dies erlaubt. Eine dedizierte Datenbankverbindung, die garantiert nicht von anderen Threads mitgenutzt wird, fordern Sie wie folgt an:
db = pool.connection(shareable=False)
Stattdessen knnen Sie eine dedizierte Verbindung auch wie folgt erhalten:
db = pool.dedicated_connection()
Wenn Sie die Datenbankverbindung nicht mehr bentigen, sollten Sie diese sofort wieder mit db.close() an den Pool zurckgeben. Sie knnen auf die gleiche Weise eine neue Verbindung erhalten.
Warnung
In einer Multithread-Umgebung benutzen Sie niemals:
pool.connection().cursor().execute(...)
Dies wrde die Datenbankverbindung zu frh zur Wiederverwendung zurckgeben, was fatale Folgen haben knnte, wenn die Verbindungen nicht thread-sicher sind. Stellen Sie sicher, dass die Verbindungsobjekte so lange vorhanden sind, wie sie gebraucht werden, etwa so:
db = pool.connection() cur = db.cursor() cur.execute(...) res = cur.fetchone() cur.close() # oder del cur db.close() # oder del db
Sie knnen dies auch durch Verwendung von Kontext-Managern vereinfachen:
with pool.connection() as db:
with db.cursor() as cur:
cur.execute(...)
res = cur.fetchone()
Warnung
Bitte beachten Sie, dass Transaktionen explizit durch Aufruf der Methode begin() eingeleitet werden mssen. Hierdurch wird sichergestellt, dass die Verbindung nicht mehr mit anderen Threads geteilt wird, dass das transparente Neuerffnen von Verbindungen bis zum Ende der Transaktion ausgesetzt wird, und dass die Verbindung zurckgerollt wird, bevor sie wieder an den Verbindungspool zurckgegeben wird.
Manchmal mchte man Datenbankverbindungen besonders vorbereiten, bevor sie von DBUtils verwendet werden, und dies ist nicht immer durch Verwendung der passenden Parameter mglich. Zum Beispiel kann es pyodbc erfordern, dass man die Methode setencoding() der Datenbankverbindung aufruft. Sie knnen dies erreichen, indem Sie eine modifizierte Version der Funktion connect() verwenden und diese als creator (dem ersten Argument) an PersistentDB oder PooledDB bergeben, etwa so:
import pyodbc
from dbutils.pooled_db import PooledDB
def creator():
con = pyodbc.connect(...)
con.setencoding(...)
return con
creator.dbapi = pyodbc
db_pool = PooledDB(creator, mincached=5)
Wenn eine Datenbankoperation mit einer der im Parameter failures angegebenen Exception-Klassen fehlschlgt, dann nimmt DBUtils an, dass die Verbindung verloren gegangen ist, und wiederholt die Operation transparent, zunchst mit einem neuen Cursor und danach mit einer neu geffneten Verbindung. Genau das mchte man, wenn der Datenbankserver neu gestartet wurde, aber nicht, wenn die Anweisung selbst aus einem Grund fehlgeschlagen ist, der nichts mit dem Zustand der Verbindung zu tun hat.
Leider melden viele Datenbankadapter-Module beide Arten von Problemen mit derselben Exception-Klasse. Wenn zum Beispiel MySQL eine Anweisung abbricht, weil diese eine absichtlich angeforderte Zeitbegrenzung berschritten hat:
cur.execute('SELECT /*+ MAX_EXECUTION_TIME(10000) */ ...')
dann lst pymysql einen OperationalError aus, genau wie beim tatschlichen Verlust der Verbindung. Da der Parameter failures nur Exception-Klassen angeben kann und Python Unterklassen nicht von einer except-Klausel ausschlieen kann, lsst sich diese Unterscheidung nicht durch eine Einschrnkung des Parameters failures ausdrcken. Im obigen Beispiel wrde die Anweisung bis zu dreimal ausgefhrt, und die Abfrage wrde bis zu 30 statt 10 Sekunden dauern.
Fr solche Flle knnen Sie eine Funktion als isfatal bergeben, die fr jeden zu failures passenden Fehler gefragt wird, ob dieser fr die Verbindung wirklich fatal ist:
import pymysql
from dbutils.pooled_db import PooledDB
def no_timeout(error):
# 3024 = Zeitbegrenzung berschritten, die Verbindung ist noch intakt
return not error.args or error.args[0] != 3024
pool = PooledDB(pymysql, 5, database='mydb', isfatal=no_timeout)
Wenn die Funktion einen falschen Wert zurckgibt, dann gilt der Fehler als nicht fatal, wird also sofort an die Anwendung weitergegeben, und die Verbindung wird weder ersetzt noch aus dem Verbindungspool entfernt. Beachten Sie, dass isfatal als Schlsselwort-Argument bergeben werden muss und mit beliebigen Exceptions der als failures angegebenen Klassen umgehen knnen muss.
Wenn Sie die Ausfallsicherung nur fr eine bestimmte Anweisung abschalten mchten, statt sie fr den gesamten Verbindungspool zu konfigurieren, dann knnen Sie den Kontextmanager no_failover() des Cursors verwenden:
with pool.connection() as db:
with db.cursor() as cur:
with cur.no_failover():
cur.execute('SELECT /*+ MAX_EXECUTION_TIME(10000) */ ...')
rows = cur.fetchall()
Alles brige, insbesondere die ping()-Prfung und die Zhlung der Verwendungen der zugrunde liegenden Verbindung, bleibt innerhalb dieses Kontexts unverndert.
Als letztes Mittel knnen Sie ber das Attribut dbapi_connection einer Verbindung und das Attribut dbapi_cursor eines Cursors auch direkt auf die zugrunde liegenden DB-API-2-Objekte zugreifen. Beachten Sie, dass Operationen auf diesen Objekten berhaupt nicht von der Ausfallsicherung erfasst und auch nicht auf die Begrenzung maxusage angerechnet werden.
Warnung
Statt der obigen Mglichkeiten knnen Sie auch einfach mit der Methode begin() eine Transaktion starten, da die Ausfallsicherung whrend einer Transaktion stets ausgesetzt wird. Bedenken Sie aber, dass dadurch tatschlich eine Transaktion auf dem Datenbankserver gestartet wird, mit allen sich daraus ergebenden Folgen.
Verbindungen, die im Verbindungspool gehalten oder einem Thread zugeordnet sind, knnen unbrauchbar werden, wenn der Datenbankserver neu gestartet wird oder zu lange unttige Verbindungen abbricht. Damit dies auffllt, bevor die Verbindung verwendet wird, kann DBUtils sie mit der ping()-Methode der zugrunde liegenden DB-API-2-Verbindung prfen, wobei der Parameter ping festlegt, wann eine solche Prfung stattfindet.
Allerdings ist ping() nicht Teil der DB-API-2-Spezifikation, und viele gebruchliche Datenbankadapter-Module stellen diese Methode nicht bereit. Sobald DBUtils bemerkt, dass die Methode nicht verfgbar ist, werden die Verbindungen berhaupt nicht mehr geprft. In diesem Fall knnen Sie als Parameter ping einen SQL-Befehl angeben, der stattdessen zur Prfung der Verbindung ausgefhrt werden soll:
import psycopg2 from dbutils.pooled_db import PooledDB pool = PooledDB(psycopg2, 5, database='meinedb', ping='select 1')
Statt eines SQL-Befehls knnen Sie auch eine Funktion angeben, der die zugrunde liegende DB-API-2-Verbindung bergeben wird und die zurckgibt, ob diese noch intakt ist:
def is_healthy(con):
# psycopg2 wei, ob die Verbindung bereits geschlossen wurde
return not con.closed
pool = PooledDB(psycopg2, 5, database='meinedb', ping=is_healthy)
Die Rckgabe von None gilt als intakt, das Auslsen einer Exception als nicht intakt, so dass auch eine Funktion verwendet werden kann, die einfach eine Datenbankoperation ausfhrt, ohne Fehler abzufangen. Meldet die Prfung die Verbindung als nicht intakt, dann wird diese transparent durch eine neu geffnete Verbindung ersetzt, genau wie wenn ping() sie als nicht mehr brauchbar gemeldet htte.
Eine solche Prfung findet immer dann statt, wenn eine Verbindung aus dem Verbindungspool geholt oder von einem Thread angefragt wird, also zu dem Zeitpunkt, der dem Wert ping=1 entspricht. Wenn sie auch zu den anderen Zeitpunkten stattfinden soll, dann geben Sie ein Tupel aus dem blichen ganzzahligen Wert und dem SQL-Befehl oder der Funktion an:
pool = PooledDB(psycopg2, 5, database='meinedb', ping=(4, 'select 1'))
Warnung
Jede derartige Prfung erfordert eine zustzliche Anfrage an den Datenbankserver, weshalb Sie sie nur bei wirklichem Bedarf mit ping=4 oder ping=7 kombinieren sollten. Bedenken Sie auerdem, dass ein zur Prfung ausgefhrter SQL-Befehl eine Transaktion auf dem Datenbankserver starten kann, wenn die Verbindung nicht im Autocommit-Modus luft.
Wenn Sie einen der bekannten "Object-Relational Mapper" SQLObject oder SQLAlchemy verwenden, dann bentigen Sie DBUtils nicht, denn diese haben ihre eigenen Mechanismen zum Pooling von Datenbankverbindungen eingebaut. Tatschlich hat SQLObject 2 (SQL-API) das Pooling in eine separate Schicht ausgelagert, in der Code von DBUtils verwendet wird.
Wenn Sie eine Lsung verwenden wie den Apache-Webserver mit mod_python oder mod_wsgi, dann sollten Sie bedenken, dass Ihr Python-Code normalerweise im Kontext der Kindprozesse des Webservers luft. Wenn Sie also das pooled_db-Modul einsetzen, und mehrere dieser Kindprozesse laufen, dann werden Sie ebenso viele Pools mit Datenbankverbindungen erhalten. Wenn diese Prozesse viele Threads laufen lassen, dann mag dies ein sinnvoller Ansatz sein, wenn aber diese Prozesse nicht mehr als einen Worker-Thread starten, wie im Fall des Multi-Processing-Moduls "prefork" fr den Apache-Webserver, dann sollten Sie auf eine Middleware fr das Connection-Pooling zurckgreifen, die Multi-Processing untersttzt, wie zum Beispiel pgpool oder pgbouncer fr die PostgreSQL-Datenbank.
Einige Ideen fr zuknftige Verbesserungen:
Alternativ zur Obergrenze in der Anzahl der Nutzung einer Datenbankverbindung knnte eine maximale Lebensdauer fr die Verbindung implementiert werden.
Es knnten Module monitor_db und monitor_pg hinzugefgt werden, die in einem separaten Thread stndig den "idle pool" und eventuell auch den "shared pool" bzw. die persistenten Verbindungen berwachen. Wenn eine unterbrochene Datenbankverbindung entdeckt wird, wird diese automatisch durch den Monitor-Thread wiederhergestellt. Dies ist in einem Szenario sinnvoll, bei dem die Datenbank einer Website jede Nacht neu gestartet wird. Ohne den Monitor-Thread wrden die Benutzer morgens eine kleine Verzgerung bemerken, weil erst dann die unterbrochenen Datenbankverbindungen entdeckt wrden und sich der Pool langsam wieder neu aufbaut. Mit dem Monitor-Thread wrde dies schon whrend der Nacht passieren, kurz nach der Unterbrechung. Der Monitor-Thread knnte auch so konfiguriert werden, dass er generell tglich den Verbindungspool erneuert, kurz bevor die Benutzer erscheinen.
Optional sollten Benutzung, schlechte Verbindungen und berschreitung von Obergrenzen in Logs gespeichert werden knnen.
Fehlermeldungen, Patches und Feedback knnen Sie als Issues oder Pull Requests auf der GitHub-Projektseite von DBUtils bermitteln.
Einige Links zu verwandter und alternativer Software:
Webware for Python Framework
Python DB-API 2
PostgreSQL Datenbank
PyGreSQL Python-Adapter fr PostgreSQL
pgpool Middleware fr Connection-Pooling mit PostgreSQL
pgbouncer Middleware fr Connection-Pooling mit PostgreSQL
SQLObject Objekt-relationaler Mapper
SQLAlchemy Objekt-relationaler Mapper
DBUtils benutzt Code, Anmerkungen und Vorschlge von Ian Bicking, Chuck Esterbrook (Webware for Python), Dan Green (DBTools), Jay Love, Michael Palmer, Tom Schwaller, Geoffrey Talvola, Warren Smith (DbConnectionPool), Ezio Vernacotola, Jehiah Czebotar, Matthew Harriger, Gregory Piero und Josef van Eenbergen.
Copyright 2005-2025 Christoph Zwerschke. Alle Rechte vorbehalten.
DBUtils ist freie und quelloffene Software, lizenziert unter der MIT-Lizenz.
| Web Proxy Viewer | New URL | Original Page |