Connection Pooling

Ein Connection Pool ist eine gängige Technik, um langlebige Verbindungen im Speicher für effiziente Wiederverwendung zu halten, sowie zur Verwaltung der Gesamtzahl von Verbindungen, die eine Anwendung gleichzeitig verwenden kann.

Insbesondere für serverseitige Webanwendungen ist ein Connection Pool die Standardmethode, um einen „Pool“ aktiver Datenbankverbindungen im Speicher zu unterhalten, die über Anfragen hinweg wiederverwendet werden.

SQLAlchemy enthält mehrere Connection-Pool-Implementierungen, die sich mit der Engine integrieren. Sie können auch direkt für Anwendungen verwendet werden, die einem ansonsten einfachen DBAPI-Ansatz Pooling hinzufügen möchten.

Konfiguration des Connection Pools

Die von der Funktion create_engine() zurückgegebene Engine hat in den meisten Fällen einen integrierten QueuePool, der mit sinnvollen Standardwerten für das Pooling vorkonfiguriert ist. Wenn Sie diesen Abschnitt nur lesen, um zu erfahren, wie Sie Pooling aktivieren – herzlichen Glückwunsch! Sie sind bereits fertig.

Die gebräuchlichsten Tuning-Parameter des QueuePool können direkt als Schlüsselwortargumente an create_engine() übergeben werden: pool_size, max_overflow, pool_recycle und pool_timeout. Zum Beispiel

engine = create_engine(
    "postgresql+psycopg2://me@localhost/mydb", pool_size=20, max_overflow=0
)

Alle SQLAlchemy-Pool-Implementierungen haben gemeinsam, dass keine von ihnen Verbindungen „vorkonfiguriert“ – alle Implementierungen warten bis zur ersten Verwendung, bevor eine Verbindung erstellt wird. Zu diesem Zeitpunkt, wenn keine zusätzlichen gleichzeitigen Checkout-Anfragen für mehr Verbindungen erfolgen, werden keine zusätzlichen Verbindungen erstellt. Deshalb ist es vollkommen in Ordnung, dass create_engine() standardmäßig einen QueuePool der Größe fünf verwendet, ohne Rücksicht darauf, ob die Anwendung wirklich fünf Verbindungen benötigt – der Pool würde nur bis zu dieser Größe wachsen, wenn die Anwendung tatsächlich fünf Verbindungen gleichzeitig verwendet, in welchem Fall die Verwendung eines kleinen Pools ein völlig angemessenes Standardverhalten ist.

Hinweis

Die Klasse QueuePool ist nicht mit asyncio kompatibel. Bei der Verwendung von create_async_engine zum Erstellen einer Instanz von AsyncEngine wird stattdessen die Klasse AsyncAdaptedQueuePool verwendet, die eine mit asyncio kompatible Warteschlangenimplementierung nutzt.

Wechseln von Pool-Implementierungen

Der übliche Weg, eine andere Art von Pool mit create_engine() zu verwenden, ist die Verwendung des Arguments poolclass. Dieses Argument akzeptiert eine Klasse, die aus dem Modul sqlalchemy.pool importiert wird, und kümmert sich um die Details des Pool-Aufbaus für Sie. Ein häufiger Anwendungsfall ist, wenn das Connection-Pooling deaktiviert werden soll, was durch die Verwendung der Implementierung NullPool erreicht werden kann.

from sqlalchemy.pool import NullPool

engine = create_engine(
    "postgresql+psycopg2://scott:tiger@localhost/test", poolclass=NullPool
)

Verwenden einer benutzerdefinierten Verbindungsfunktion

Siehe den Abschnitt Benutzerdefinierte DBAPI connect() Argumente / On-Connect Routinen für eine Übersicht über die verschiedenen Routinen zur Verbindungsanpassung.

Konstruieren eines Pools

Um einen Pool eigenständig zu verwenden, ist die Funktion creator das einzige erforderliche Argument und wird zuerst übergeben, gefolgt von beliebigen zusätzlichen Optionen.

import sqlalchemy.pool as pool
import psycopg2


def getconn():
    c = psycopg2.connect(user="ed", host="127.0.0.1", dbname="test")
    return c


mypool = pool.QueuePool(getconn, max_overflow=10, pool_size=5)

DBAPI-Verbindungen können dann über die Funktion Pool.connect() aus dem Pool beschafft werden. Der Rückgabewert dieser Methode ist eine DBAPI-Verbindung, die in einem transparenten Proxy enthalten ist.

# get a connection
conn = mypool.connect()

# use it
cursor_obj = conn.cursor()
cursor_obj.execute("select foo")

Der Zweck des transparenten Proxys besteht darin, den close()-Aufruf abzufangen, so dass anstatt die DBAPI-Verbindung zu schließen, diese an den Pool zurückgegeben wird.

# "close" the connection.  Returns
# it to the pool.
conn.close()

Der Proxy gibt seine enthaltene DBAPI-Verbindung auch an den Pool zurück, wenn er vom Garbage Collector bereinigt wird, obwohl es in Python nicht deterministisch ist, dass dies sofort geschieht (obwohl es bei cPython typisch ist). Diese Verwendung wird jedoch nicht empfohlen und ist insbesondere bei asyncio DBAPI-Treibern nicht unterstützt.

Reset On Return

Der Pool enthält ein „reset on return“-Verhalten, das die Methode rollback() der DBAPI-Verbindung aufruft, wenn die Verbindung an den Pool zurückgegeben wird. Dies geschieht, damit jeglicher vorhandene transaktionale Zustand von der Verbindung entfernt wird, was nicht nur unbestätigte Daten, sondern auch Tabellen- und Zeilensperren einschließt. Für die meisten DBAPIs ist der Aufruf von rollback() kostengünstig, und wenn die DBAPI bereits eine Transaktion abgeschlossen hat, sollte die Methode keine Wirkung haben (no-op).

Zurücksetzen bei Rückgabe für nicht-transaktionale Verbindungen deaktivieren

In sehr spezifischen Fällen, in denen dieses rollback() nicht nützlich ist, z. B. bei Verwendung einer Verbindung, die für Autocommit konfiguriert ist, oder bei Verwendung einer Datenbank ohne ACID-Fähigkeiten wie der MyISAM-Engine von MySQL, kann das Reset-on-Return-Verhalten aus Leistungsgründen deaktiviert werden. Dies kann durch Verwendung des Parameters Pool.reset_on_return von Pool erreicht werden, der auch von create_engine() als create_engine.pool_reset_on_return verfügbar ist, indem der Wert None übergeben wird. Dies wird im folgenden Beispiel veranschaulicht, zusammen mit der Einstellung des Parameters create_engine.isolation_level auf AUTOCOMMIT.

non_acid_engine = create_engine(
    "mysql://scott:tiger@host/db",
    pool_reset_on_return=None,
    isolation_level="AUTOCOMMIT",
)

Die obige Engine führt beim Zurückgeben von Verbindungen an den Pool tatsächlich kein ROLLBACK durch; da AUTOCOMMIT aktiviert ist, führt der Treiber auch keinen BEGIN-Vorgang durch.

Benutzerdefinierte Reset-on-Return-Schemata

Ein „reset on return“, das aus einem einzigen rollback() besteht, ist möglicherweise nicht ausreichend für einige Anwendungsfälle; insbesondere Anwendungen, die temporäre Tabellen verwenden, möchten möglicherweise, dass diese Tabellen beim Einchecken von Verbindungen automatisch entfernt werden. Einige (aber insbesondere nicht alle) Backends enthalten Funktionen, die solche Tabellen im Geltungsbereich einer Datenbankverbindung „zurücksetzen“ können, was ein wünschenswertes Verhalten für das Zurücksetzen von Connection-Pools sein kann. Andere Serverressourcen wie vorbereitete Anweisungshandles und serverseitige Anweisungscaches können über den Eincheck-Prozess hinaus bestehen bleiben, was je nach Einzelheiten wünschenswert sein kann oder auch nicht. Auch hier können einige (aber wieder nicht alle) Backends eine Möglichkeit bieten, diesen Zustand zurückzusetzen. Die beiden von SQLAlchemy enthaltenen Dialekte, die solche Reset-Schemata aufweisen, sind Microsoft SQL Server, wo eine undokumentierte, aber weithin bekannte gespeicherte Prozedur namens sp_reset_connection oft verwendet wird, und PostgreSQL, das eine gut dokumentierte Reihe von Befehlen hat, einschließlich DISCARD RESET, DEALLOCATE und UNLISTEN.

Das folgende Beispiel veranschaulicht, wie das Zurücksetzen bei Rückgabe durch die Microsoft SQL Server gespeicherte Prozedur sp_reset_connection mithilfe des Event-Hooks PoolEvents.reset() ersetzt wird. Der Parameter create_engine.pool_reset_on_return wird auf None gesetzt, damit das benutzerdefinierte Schema das Standardverhalten vollständig ersetzen kann. Die benutzerdefinierte Hook-Implementierung ruft in jedem Fall .rollback() auf, da es normalerweise wichtig ist, dass die eigene Verfolgung von Commit/Rollback durch die DBAPI mit dem Zustand der Transaktion übereinstimmt.

from sqlalchemy import create_engine
from sqlalchemy import event

mssql_engine = create_engine(
    "mssql+pyodbc://scott:tiger^5HHH@mssql2017:1433/test?driver=ODBC+Driver+17+for+SQL+Server",
    # disable default reset-on-return scheme
    pool_reset_on_return=None,
)


@event.listens_for(mssql_engine, "reset")
def _reset_mssql(dbapi_connection, connection_record, reset_state):
    if not reset_state.terminate_only:
        dbapi_connection.execute("{call sys.sp_reset_connection}")

    # so that the DBAPI itself knows that the connection has been
    # reset
    dbapi_connection.rollback()

Geändert in Version 2.0.0b3: Zusätzliche Zustandsargumente für das Ereignis PoolEvents.reset() hinzugefügt und zusätzlich sichergestellt, dass das Ereignis für alle „Reset“-Vorkommen ausgelöst wird, sodass es als Ort für benutzerdefinierte „Reset“-Handler geeignet ist. Frühere Schemata, die den PoolEvents.checkin()-Handler verwenden, bleiben ebenfalls nutzbar.

Protokollieren von Reset-on-Return-Ereignissen

Die Protokollierung für Pool-Ereignisse, einschließlich Reset on Return, kann auf dem Protokollierungslevel logging.DEBUG zusammen mit dem Logger sqlalchemy.pool eingestellt werden, oder indem create_engine.echo_pool auf "debug" gesetzt wird, wenn create_engine() verwendet wird.

>>> from sqlalchemy import create_engine
>>> engine = create_engine("postgresql://scott:tiger@localhost/test", echo_pool="debug")

Der obige Pool zeigt ausführliche Protokollierung, einschließlich Reset on Return.

>>> c1 = engine.connect()
DEBUG sqlalchemy.pool.impl.QueuePool Created new connection <connection object ...>
DEBUG sqlalchemy.pool.impl.QueuePool Connection <connection object ...> checked out from pool
>>> c1.close()
DEBUG sqlalchemy.pool.impl.QueuePool Connection <connection object ...> being returned to pool
DEBUG sqlalchemy.pool.impl.QueuePool Connection <connection object ...> rollback-on-return

Pool-Ereignisse

Connection-Pools unterstützen eine Ereignisschnittstelle, die es Hooks ermöglicht, beim ersten Verbindungsaufbau, bei jeder neuen Verbindung sowie beim Auschecken und Einchecken von Verbindungen ausgeführt zu werden. Details finden Sie unter PoolEvents.

Umgang mit Verbindungsabbrüchen

Der Connection-Pool verfügt über die Möglichkeit, einzelne Verbindungen sowie den gesamten Satz von Verbindungen zu aktualisieren und die zuvor gepoolten Verbindungen als „ungültig“ zu kennzeichnen. Ein häufiger Anwendungsfall ist es, dem Connection-Pool zu ermöglichen, sich ordnungsgemäß zu erholen, wenn der Datenbankserver neu gestartet wurde und alle zuvor aufgebauten Verbindungen nicht mehr funktionsfähig sind. Es gibt zwei Ansätze dafür.

Umgang mit Verbindungsabbrüchen - Pessimistisch

Der pessimistische Ansatz bezieht sich darauf, eine Testanweisung auf der SQL-Verbindung zu Beginn jedes Connection-Pool-Checkouts auszugeben, um zu testen, ob die Datenbankverbindung noch gültig ist. Die Implementierung ist Dialekt-spezifisch und verwendet entweder eine DBAPI-spezifische Ping-Methode oder eine einfache SQL-Anweisung wie „SELECT 1“, um die Verbindung auf Lebensfähigkeit zu testen.

Dieser Ansatz fügt dem Checkout-Prozess von Verbindungen eine geringfügige Mehrbelastung hinzu, ist aber ansonsten der einfachste und zuverlässigste Ansatz, um Datenbankfehler aufgrund veralteter gepoolter Verbindungen vollständig zu eliminieren. Die aufrufende Anwendung muss sich keine Gedanken über die Organisation von Operationen machen, um sich von veralteten Verbindungen zu erholen, die aus dem Pool ausgecheckt wurden.

Das pessimistische Testen von Verbindungen beim Checkout ist durch die Verwendung des Arguments Pool.pre_ping möglich, das von create_engine() über das Argument create_engine.pool_pre_ping verfügbar ist.

engine = create_engine("mysql+pymysql://user:pw@host/db", pool_pre_ping=True)

Die „pre-ping“-Funktion arbeitet pro Dialekt, entweder durch Aufrufen einer DBAPI-spezifischen „ping“-Methode oder, falls nicht verfügbar, durch Ausgeben von SQL, das „SELECT 1“ entspricht. Dabei werden Fehler abgefangen und der Fehler als „Disconnect“-Situation erkannt. Wenn der Ping-/Fehlercheck ergibt, dass die Verbindung nicht nutzbar ist, wird die Verbindung sofort neu gestartet und alle anderen gepoolten Verbindungen, die älter als die aktuelle Zeit sind, werden ungültig gemacht, sodass sie beim nächsten Checkout ebenfalls vor der Verwendung neu gestartet werden.

Wenn die Datenbank beim Ausführen von „pre-ping“ immer noch nicht verfügbar ist, schlägt der erste Verbindungsaufbau fehl und der Fehler für den Verbindungsfehler wird normal weitergegeben. In der seltenen Situation, dass die Datenbank für Verbindungen verfügbar ist, aber nicht auf einen „Ping“ reagieren kann, versucht „pre_ping“ bis zu dreimal, bevor es aufgibt und den zuletzt empfangenen Datenbankfehler weitergibt.

Es ist wichtig zu beachten, dass der Pre-Ping-Ansatz keine Verbindungen berücksichtigt, die mitten in Transaktionen oder anderen SQL-Operationen unterbrochen wurden. Wenn die Datenbank während einer laufenden Transaktion nicht verfügbar wird, geht die Transaktion verloren und der Datenbankfehler wird ausgelöst. Während das Connection-Objekt eine „Disconnect“-Situation erkennt und die Verbindung neu startet sowie den Rest des Verbindungspools ungültig macht, wenn diese Bedingung auftritt, geht die einzelne Operation, bei der die Ausnahme ausgelöst wurde, verloren, und es liegt an der Anwendung, entweder die Operation abzubrechen oder die gesamte Transaktion erneut zu versuchen. Wenn die Engine mit DBAPI-basiertem Autocommit konfiguriert ist, wie in Festlegen von Transaktionsisolationsstufen, einschließlich DBAPI-Autocommit beschrieben, kann eine Verbindung möglicherweise transparent mitten in einer Operation mit Ereignissen neu verbunden werden. Siehe den Abschnitt Wie kann ich eine Anweisungsausführung automatisch „wiederholen“? für ein Beispiel.

Für Dialekte, die „SELECT 1“ verwenden und Fehler abfangen, um Disconnects zu erkennen, kann der Disconnect-Test für neue Back-End-spezifische Fehlermeldungen mit dem Hook DialectEvents.handle_error() erweitert werden.

Benutzerdefinierter / Legacy Pessimistic Ping

Bevor create_engine.pool_pre_ping hinzugefügt wurde, wurde der „Pre-Ping“-Ansatz historisch manuell mit dem Engine-Ereignis ConnectionEvents.engine_connect() durchgeführt. Das gängigste Rezept dafür ist unten aufgeführt, zu Referenzzwecken, falls eine Anwendung bereits ein solches Rezept verwendet oder spezielle Verhaltensweisen benötigt.

from sqlalchemy import exc
from sqlalchemy import event
from sqlalchemy import select

some_engine = create_engine(...)


@event.listens_for(some_engine, "engine_connect")
def ping_connection(connection, branch):
    if branch:
        # this parameter is always False as of SQLAlchemy 2.0,
        # but is still accepted by the event hook.  In 1.x versions
        # of SQLAlchemy, "branched" connections should be skipped.
        return

    try:
        # run a SELECT 1.   use a core select() so that
        # the SELECT of a scalar value without a table is
        # appropriately formatted for the backend
        connection.scalar(select(1))
    except exc.DBAPIError as err:
        # catch SQLAlchemy's DBAPIError, which is a wrapper
        # for the DBAPI's exception.  It includes a .connection_invalidated
        # attribute which specifies if this connection is a "disconnect"
        # condition, which is based on inspection of the original exception
        # by the dialect in use.
        if err.connection_invalidated:
            # run the same SELECT again - the connection will re-validate
            # itself and establish a new connection.  The disconnect detection
            # here also causes the whole connection pool to be invalidated
            # so that all stale connections are discarded.
            connection.scalar(select(1))
        else:
            raise

Das obige Rezept hat den Vorteil, dass wir die Einrichtungen von SQLAlchemy nutzen, um jene DBAPI-Ausnahmen zu erkennen, die bekanntermaßen eine „Disconnect“-Situation anzeigen, sowie die Fähigkeit des Engine-Objekts, den aktuellen Connection-Pool bei dieser Bedingung korrekt ungültig zu machen und der aktuellen Connection zu ermöglichen, sich auf eine neue DBAPI-Verbindung neu zu validieren.

Umgang mit Verbindungsabbrüchen - Optimistisch

Wenn keine pessimistische Behandlung angewendet wird, sowie wenn die Datenbank mitten in der Nutzungsdauer einer Verbindung innerhalb einer Transaktion heruntergefahren und/oder neu gestartet wird, ist der andere Ansatz zum Umgang mit veralteten / geschlossenen Verbindungen, SQLAlchemy die Disconnects behandeln zu lassen, sobald sie auftreten. Zu diesem Zeitpunkt werden alle Verbindungen im Pool ungültig gemacht, was bedeutet, dass sie als veraltet angenommen werden und bei der nächsten Abholung aktualisiert werden. Dieses Verhalten setzt voraus, dass der Pool in Verbindung mit einer Engine verwendet wird. Die Engine verfügt über Logik, die Disconnect-Ereignisse erkennen und den Pool automatisch aktualisieren kann.

Wenn die Connection versucht, eine DBAPI-Verbindung zu verwenden, und eine Ausnahme ausgelöst wird, die einem „Disconnect“-Ereignis entspricht, wird die Verbindung ungültig gemacht. Die Connection ruft dann die Methode Pool.recreate() auf, wodurch effektiv alle Verbindungen ungültig gemacht werden, die nicht gerade ausgecheckt sind, damit sie bei der nächsten Abholung durch neue ersetzt werden. Dieser Ablauf wird durch das folgende Codebeispiel veranschaulicht.

from sqlalchemy import create_engine, exc

e = create_engine(...)
c = e.connect()

try:
    # suppose the database has been restarted.
    c.execute(text("SELECT * FROM table"))
    c.close()
except exc.DBAPIError as e:
    # an exception is raised, Connection is invalidated.
    if e.connection_invalidated:
        print("Connection was invalidated!")

# after the invalidate event, a new connection
# starts with a new Pool
c = e.connect()
c.execute(text("SELECT * FROM table"))

Das obige Beispiel veranschaulicht, dass keine besondere Intervention erforderlich ist, um den Pool zu aktualisieren, der nach Erkennung eines Disconnect-Ereignisses normal weiterläuft. Allerdings wird pro Verbindung, die während des Auftretens des Datenbank-Nichtverfügbarkeitsereignisses in Gebrauch ist, eine Datenbankausnahme ausgelöst. In einer typischen Webanwendung, die eine ORM-Session verwendet, würde die obige Bedingung einer einzelnen Anfrage entsprechen, die mit einem 500er-Fehler fehlschlägt, und die Webanwendung läuft danach normal weiter. Daher ist der Ansatz „optimistisch“, da häufige Datenbank-Neustarts nicht erwartet werden.

Setzen von Pool Recycle

Eine zusätzliche Einstellung, die den „optimistischen“ Ansatz ergänzen kann, ist das Setzen des Parameters pool_recycle. Dieser Parameter verhindert, dass der Pool eine bestimmte Verbindung verwendet, die ein bestimmtes Alter überschritten hat, und ist für Datenbank-Backends wie MySQL geeignet, die Verbindungen, die nach einer bestimmten Zeitspanne inaktiv waren, automatisch schließen.

from sqlalchemy import create_engine

e = create_engine("mysql+mysqldb://scott:tiger@localhost/test", pool_recycle=3600)

Oben wird jede DBAPI-Verbindung, die länger als eine Stunde geöffnet war, ungültig gemacht und bei der nächsten Abholung ersetzt. Beachten Sie, dass die Ungültigmachung nur während des Checkouts erfolgt – nicht bei Verbindungen, die in einem ausgecheckten Zustand gehalten werden. pool_recycle ist eine Funktion des Pool selbst, unabhängig davon, ob eine Engine verwendet wird oder nicht.

Mehr über Invalidation

Der Pool bietet „Connection-Invalidation“-Dienste, die sowohl eine explizite Ungültigmachung einer Verbindung als auch eine automatische Ungültigmachung als Reaktion auf Bedingungen ermöglichen, die eine Verbindung unbrauchbar machen.

„Invalidation“ bedeutet, dass eine bestimmte DBAPI-Verbindung aus dem Pool entfernt und verworfen wird. Die Methode .close() wird auf dieser Verbindung aufgerufen, wenn nicht klar ist, dass die Verbindung selbst möglicherweise nicht geschlossen wurde. Wenn diese Methode jedoch fehlschlägt, wird die Ausnahme protokolliert, aber die Operation wird trotzdem fortgesetzt.

Bei Verwendung einer Engine ist die Methode Connection.invalidate() der übliche Einstiegspunkt für die explizite Ungültigmachung. Andere Bedingungen, unter denen eine DBAPI-Verbindung ungültig gemacht werden kann, sind:

  • eine DBAPI-Ausnahme wie OperationalError, die ausgelöst wird, wenn eine Methode wie connection.execute() aufgerufen wird, als eine sogenannte „Disconnect“-Bedingung erkannt wird. Da die Python DBAPI kein standardisiertes System zur Bestimmung der Art einer Ausnahme bietet, enthalten alle SQLAlchemy-Dialekte ein System namens is_disconnect(), das den Inhalt eines Ausnahmeobjekts, einschließlich der Zeichenfolge und etwaiger Fehlermeldungen, untersucht, um festzustellen, ob diese Ausnahme anzeigt, dass die Verbindung nicht mehr verwendbar ist. Wenn dies der Fall ist, wird die Methode _ConnectionFairy.invalidate() aufgerufen und die DBAPI-Verbindung wird dann verworfen.

  • Wenn die Verbindung an den Pool zurückgegeben wird und der Aufruf der Methoden connection.rollback() oder connection.commit(), wie vom „reset on return“-Verhalten des Pools diktiert, eine Ausnahme auslöst. Ein letzter Versuch, .close() auf der Verbindung aufzurufen, wird unternommen, und sie wird dann verworfen.

  • Wenn ein Listener, der PoolEvents.checkout() implementiert, die Ausnahme DisconnectionError auslöst, was bedeutet, dass die Verbindung nicht verwendbar ist und ein neuer Verbindungsversuch unternommen werden muss.

Alle auftretenden Ungültigmachungen lösen das Ereignis PoolEvents.invalidate() aus.

Unterstützung neuer Datenbankfehlercodes für Disconnect-Szenarien

Jeder SQLAlchemy-Dialekt enthält eine Routine namens is_disconnect(), die aufgerufen wird, wenn eine DBAPI-Ausnahme auftritt. Das DBAPI-Ausnahmeobjekt wird an diese Methode übergeben, wo dialektspezifische Heuristiken dann bestimmen, ob der empfangene Fehlercode anzeigt, dass die Datenbankverbindung „getrennt“ wurde oder sich in einem anderweitig unbrauchbaren Zustand befindet, der eine Wiederverwendung anzeigt. Die hier angewandten Heuristiken können mit dem DialectEvents.handle_error() Event-Hook angepasst werden, der normalerweise über das besitzende Engine-Objekt eingerichtet wird. Mit diesem Hook werden alle auftretenden Fehler weitergegeben, wobei ein kontextbezogenes Objekt namens ExceptionContext übergeben wird. Benutzerdefinierte Event-Hooks können steuern, ob ein bestimmter Fehler als „Disconnect“-Situation betrachtet werden soll oder nicht, sowie ob dieser Disconnect den gesamten Connection-Pool ungültig machen soll oder nicht.

Um beispielsweise die Oracle Database-Treiberfehlercodes DPY-1001 und DPY-4011 als Disconnect-Codes zu behandeln, fügen Sie nach der Erstellung einen Event-Handler zum Engine hinzu.

import re

from sqlalchemy import create_engine

engine = create_engine(
    "oracle+oracledb://scott:tiger@localhost:1521?service_name=freepdb1"
)


@event.listens_for(engine, "handle_error")
def handle_exception(context: ExceptionContext) -> None:
    if not context.is_disconnect and re.match(
        r"^(?:DPY-1001|DPY-4011)", str(context.original_exception)
    ):
        context.is_disconnect = True

    return None

Die oben genannte Fehlerverarbeitungsfunktion wird für alle aufgetretenen Oracle Database-Fehler aufgerufen, einschließlich derer, die beim Verwenden der Pool Pre Ping-Funktion für Backends, die auf die Behandlung von Disconnect-Fehlern angewiesen sind (neu in 2.0), abgefangen werden.

Verwendung von FIFO vs. LIFO

Die Klasse QueuePool verfügt über ein Flag namens QueuePool.use_lifo, auf das auch über create_engine() über das Flag create_engine.pool_use_lifo zugegriffen werden kann. Wenn dieses Flag auf True gesetzt wird, verhält sich die „Queue“-Funktion des Pools stattdessen wie ein „Stack“, d.h. die zuletzt in den Pool zurückgegebene Verbindung ist die erste, die bei der nächsten Anfrage verwendet wird. Im Gegensatz zum langjährigen First-In-First-Out-Verhalten des Pools, das einen Round-Robin-Effekt der seriellen Nutzung jeder Verbindung im Pool erzeugt, ermöglicht der LIFO-Modus, dass überschüssige Verbindungen im Pool untätig bleiben, sodass serverseitige Timeout-Schemata diese Verbindungen schließen können. Der Unterschied zwischen FIFO und LIFO besteht im Grunde darin, ob es wünschenswert ist, dass der Pool auch während Leerlaufzeiten einen vollständigen Satz von Verbindungen bereit hält.

engine = create_engine("postgresql://", pool_use_lifo=True, pool_pre_ping=True)

Oben verwenden wir auch das Flag create_engine.pool_pre_ping, damit serverseitig geschlossene Verbindungen vom Connection-Pool ordnungsgemäß behandelt und durch eine neue Verbindung ersetzt werden.

Beachten Sie, dass das Flag nur für die Verwendung von QueuePool gilt.

Neu in Version 1.3.

Verwendung von Connection Pools mit Multiprocessing oder os.fork()

Es ist entscheidend, dass bei der Verwendung eines Connection Pools und damit bei der Verwendung eines über create_engine() erstellten Engine die gepoolten Verbindungen **nicht an einen Fork-Prozess weitergegeben werden**. TCP-Verbindungen werden als Dateideskriptoren dargestellt, die normalerweise prozessübergreifend funktionieren, was zu gleichzeitigem Zugriff auf den Dateideskriptor von zwei oder mehr vollständig unabhängigen Python-Interpreterzuständen führt.

Abhängig von den Spezifikationen des Treibers und des Betriebssystems reichen die hier auftretenden Probleme von nicht funktionierenden Verbindungen bis hin zu Socket-Verbindungen, die von mehreren Prozessen gleichzeitig genutzt werden und zu fehlerhafter Nachrichtenübermittlung führen (letzterer Fall ist typischerweise der häufigste).

Das SQLAlchemy Engine-Objekt verweist auf einen Connection-Pool bestehender Datenbankverbindungen. Wenn dieses Objekt also in einen Kindprozess repliziert wird, ist das Ziel sicherzustellen, dass keine Datenbankverbindungen übernommen werden. Es gibt vier allgemeine Ansätze dafür:

  1. Pooling deaktivieren mit NullPool. Dies ist das einfachste Einmal-System, das verhindert, dass die Engine eine Verbindung mehr als einmal verwendet.

    from sqlalchemy.pool import NullPool
    
    engine = create_engine("mysql+mysqldb://user:pass@host/dbname", poolclass=NullPool)
  2. Rufen Sie Engine.dispose() für eine beliebige Engine auf und übergeben Sie den Parameter Engine.dispose.close mit dem Wert False während der Initialisierungsphase des Kindprozesses. Dadurch wird sichergestellt, dass der neue Prozess keine Verbindungen des Elternprozesses berührt und stattdessen mit neuen Verbindungen beginnt. **Dies ist der empfohlene Ansatz.**

    from multiprocessing import Pool
    
    engine = create_engine("mysql+mysqldb://user:pass@host/dbname")
    
    
    def run_in_process(some_data_record):
        with engine.connect() as conn:
            conn.execute(text("..."))
    
    
    def initializer():
        """ensure the parent proc's database connections are not touched
        in the new connection pool"""
        engine.dispose(close=False)
    
    
    with Pool(10, initializer=initializer) as p:
        p.map(run_in_process, data)

    Neu in Version 1.4.33: Der Parameter Engine.dispose.close wurde hinzugefügt, um den Ersatz eines Connection-Pools in einem Kindprozess zu ermöglichen, ohne die vom Elternprozess verwendeten Verbindungen zu beeinträchtigen.

  3. Rufen Sie Engine.dispose() **direkt vor** der Erstellung des Kindprozesses auf. Dies bewirkt auch, dass der Kindprozess mit einem neuen Connection-Pool beginnt, während sichergestellt wird, dass die Verbindungen des Elternprozesses nicht an den Kindprozess übertragen werden.

    engine = create_engine("mysql://user:pass@host/dbname")
    
    
    def run_in_process():
        with engine.connect() as conn:
            conn.execute(text("..."))
    
    
    # before process starts, ensure engine.dispose() is called
    engine.dispose()
    p = Process(target=run_in_process)
    p.start()
  4. Ein Event-Handler kann dem Connection-Pool zugewiesen werden, der auf übergreifend geteilte Verbindungen testet und diese ungültig macht.

    from sqlalchemy import event
    from sqlalchemy import exc
    import os
    
    engine = create_engine("...")
    
    
    @event.listens_for(engine, "connect")
    def connect(dbapi_connection, connection_record):
        connection_record.info["pid"] = os.getpid()
    
    
    @event.listens_for(engine, "checkout")
    def checkout(dbapi_connection, connection_record, connection_proxy):
        pid = os.getpid()
        if connection_record.info["pid"] != pid:
            connection_record.dbapi_connection = connection_proxy.dbapi_connection = None
            raise exc.DisconnectionError(
                "Connection record belongs to pid %s, "
                "attempting to check out in pid %s" % (connection_record.info["pid"], pid)
            )

    Oben verwenden wir einen Ansatz, der dem in Disconnect Handling - Pessimistic beschriebenen ähnelt, um eine DBAPI-Verbindung, die aus einem anderen Elternprozess stammt, als „ungültige“ Verbindung zu behandeln und den Pool zu zwingen, den Verbindungsdatensatz zu recyceln, um eine neue Verbindung herzustellen.

Die oben genannten Strategien decken den Fall ab, dass eine Engine zwischen Prozessen geteilt wird. Die oben genannten Schritte allein reichen nicht für den Fall aus, dass eine spezifische Connection prozessübergreifend geteilt wird; es ist vorzuziehen, den Geltungsbereich einer bestimmten Connection auf einen einzelnen Prozess (und Thread) zu beschränken. Es wird außerdem nicht unterstützt, jeglichen laufenden Transaktionsstatus direkt über eine Prozessgrenze hinweg zu teilen, wie z. B. ein ORM Session-Objekt, das eine Transaktion begonnen hat und aktive Connection-Instanzen referenziert; auch hier ist es vorzuziehen, neue Session-Objekte in neuen Prozessen zu erstellen.

Direkte Verwendung einer Pool-Instanz

Eine Pool-Implementierung kann direkt ohne eine Engine verwendet werden. Dies könnte in Anwendungen verwendet werden, die nur das Pool-Verhalten ohne alle anderen SQLAlchemy-Funktionen nutzen möchten. Im folgenden Beispiel wird der Standardpool für den MySQLdb-Dialekt über create_pool_from_url() abgerufen.

from sqlalchemy import create_pool_from_url

my_pool = create_pool_from_url(
    "mysql+mysqldb://", max_overflow=5, pool_size=5, pre_ping=True
)

con = my_pool.connect()
# use the connection
...
# then close it
con.close()

Wenn der zu erstellende Pool-Typ nicht angegeben ist, wird der Standardpool für den Dialekt verwendet. Um ihn direkt anzugeben, kann das Argument poolclass verwendet werden, wie im folgenden Beispiel.

from sqlalchemy import create_pool_from_url
from sqlalchemy import NullPool

my_pool = create_pool_from_url("mysql+mysqldb://", poolclass=NullPool)

API-Dokumentation - Verfügbare Pool-Implementierungen

Objektname Beschreibung

_ConnectionFairy

Proxy für eine DBAPI-Verbindung, die Rückgabe bei Dereferenzierung unterstützt.

_ConnectionRecord

Führt eine Position in einem Connection-Pool, die eine gepoolte Verbindung referenziert.

AssertionPool

Ein Pool, der zu einem bestimmten Zeitpunkt höchstens eine ausgecheckte Verbindung zulässt.

AsyncAdaptedQueuePool

Eine asyncio-kompatible Version von QueuePool.

ConnectionPoolEntry

Schnittstelle für das Objekt, das eine einzelne Datenbankverbindung im Auftrag einer Pool-Instanz verwaltet.

ManagesConnection

Gemeinsame Basis für die beiden Verbindungsmanagement-Schnittstellen PoolProxiedConnection und ConnectionPoolEntry.

NullPool

Ein Pool, der keine Verbindungen poolt.

Pool

Abstrakte Basisklasse für Connection-Pools.

PoolProxiedConnection

Ein Connection-Adapter, der einer PEP 249 DBAPI-Verbindung ähnelt und zusätzliche Methoden enthält, die für die Pool-Implementierung spezifisch sind.

QueuePool

Ein Pool, der die Anzahl der offenen Verbindungen begrenzt.

SingletonThreadPool

Ein Pool, der eine Verbindung pro Thread verwaltet.

StaticPool

Ein Pool mit genau einer Verbindung, die für alle Anfragen verwendet wird.

class sqlalchemy.pool.Pool

Abstrakte Basisklasse für Connection-Pools.

Klassensignatur

class sqlalchemy.pool.Pool (sqlalchemy.log.Identified, sqlalchemy.event.registry.EventTarget)

method sqlalchemy.pool.Pool.__init__(creator: _CreatorFnType | _CreatorWRecFnType, recycle: int = -1, echo: log._EchoFlagType = None, logging_name: str | None = None, reset_on_return: _ResetStyleArgType = True, events: List[Tuple[_ListenerFnType, str]] | None = None, dialect: _ConnDialect | Dialect | None = None, pre_ping: bool = False, _dispatch: _DispatchCommon[Pool] | None = None)

Konstruiert einen Pool.

Parameter:
  • creator – eine aufrufbare Funktion, die ein DB-API-Verbindungsobjekt zurückgibt. Die Funktion wird mit Parametern aufgerufen.

  • recycle – Wenn auf einen anderen Wert als -1 gesetzt, Anzahl der Sekunden zwischen der Wiederverwendung von Verbindungen, was bedeutet, dass beim Auschecken, wenn dieses Timeout überschritten wird, die Verbindung geschlossen und durch eine neu geöffnete Verbindung ersetzt wird. Standardmäßig -1.

  • logging_name – Zeichenketten-Identifikator, der im Feld „name“ von Protokollierungsdatensätzen verwendet wird, die im Logger „sqlalchemy.pool“ generiert werden. Standardmäßig eine Hex-Zeichenkette der Objekt-ID.

  • echo

    Wenn True, protokolliert der Connection-Pool informative Ausgaben, z. B. wenn Verbindungen ungültig gemacht werden und wenn Verbindungen recycelt werden, an den Standard-Protokollhandler, der standardmäßig sys.stdout für die Ausgabe ist. Wenn auf die Zeichenkette "debug" gesetzt, enthält die Protokollierung Pool-Checkouts und -Checkins.

    Der Parameter Pool.echo kann auch vom create_engine()-Aufruf über den Parameter create_engine.echo_pool gesetzt werden.

    Siehe auch

    Konfiguration der Protokollierung – weitere Details zur Konfiguration der Protokollierung.

  • reset_on_return

    Schritte bestimmen, die bei Verbindungen ausgeführt werden, wenn sie an den Pool zurückgegeben werden und nicht anderweitig von einer Connection behandelt wurden. Verfügbar über create_engine() über den Parameter create_engine.pool_reset_on_return.

    Pool.reset_on_return kann einen der folgenden Werte annehmen:

    • "rollback" - rollback() auf der Verbindung aufrufen, um Sperren und Transaktionsressourcen freizugeben. Dies ist der Standardwert. Die überwiegende Mehrheit der Anwendungsfälle sollte diesen Wert beibehalten.

    • "commit" - commit() auf der Verbindung aufrufen, um Sperren und Transaktionsressourcen freizugeben. Ein Commit kann hier für Datenbanken wünschenswert sein, die Query-Pläne cachen, wenn ein Commit ausgeführt wird, wie z. B. Microsoft SQL Server. Dieser Wert ist jedoch gefährlicher als 'rollback', da alle Datenänderungen, die sich in der Transaktion befinden, bedingungslos committet werden.

    • None - nichts mit der Verbindung tun. Diese Einstellung kann geeignet sein, wenn die Datenbank / DBAPI jederzeit im reinen „Autocommit“-Modus arbeitet oder wenn ein benutzerdefinierter Reset-Handler über den PoolEvents.reset() Event-Hook eingerichtet wird.

    • True - dasselbe wie 'rollback', dies ist aus Kompatibilitätsgründen vorhanden.

    • False - dasselbe wie None, dies ist aus Kompatibilitätsgründen vorhanden.

    Für weitere Anpassungen des Zurücksetzens bei Rückgabe kann der PoolEvents.reset() Event-Hook verwendet werden, der bei jedem Zurücksetzen beliebige Verbindungsaktivitäten durchführen kann.

  • events – eine Liste von 2-Tupeln, jeweils in der Form (callable, target), die bei der Konstruktion an listen() übergeben werden. Hier bereitgestellt, damit Event-Listener über create_engine() zugewiesen werden können, bevor Dialekt-Level-Listener angewendet werden.

  • dialect – ein Dialect, der die Aufgabe der Ausführung von rollback(), close() oder commit() auf DBAPI-Verbindungen übernimmt. Wenn weggelassen, wird ein integrierter „Stub“-Dialekt verwendet. Anwendungen, die create_engine() verwenden, sollten diesen Parameter nicht verwenden, da er von der Engine-Erstellungsstrategie gehandhabt wird.

  • pre_ping

    Wenn True, gibt der Pool beim Auschecken einen „Ping“ (typischerweise „SELECT 1“, aber dialektspezifisch) auf der Verbindung aus, um zu testen, ob die Verbindung lebendig ist oder nicht. Wenn nicht, wird die Verbindung transparent neu verbunden und bei Erfolg werden alle anderen vor diesem Zeitstempel hergestellten gepoolten Verbindungen ungültig gemacht. Erfordert die Übergabe eines Dialekts, um den Disconnect-Fehler zu interpretieren.

    Neu seit Version 1.2.

method sqlalchemy.pool.Pool.connect() PoolProxiedConnection

Gibt eine DBAPI-Verbindung aus dem Pool zurück.

Die Verbindung ist so instrumentiert, dass beim Aufruf ihrer close()-Methode die Verbindung an den Pool zurückgegeben wird.

method sqlalchemy.pool.Pool.dispose() None

Verwirft diesen Pool.

Diese Methode lässt die Möglichkeit offen, dass ausgecheckte Verbindungen offen bleiben, da sie nur Verbindungen betrifft, die im Pool untätig sind.

Siehe auch

Pool.recreate()

method sqlalchemy.pool.Pool.recreate() Pool

Gibt einen neuen Pool zurück, derselben Klasse wie dieser und konfiguriert mit identischen Erstellungsargumenten.

Diese Methode wird in Verbindung mit dispose() verwendet, um einen gesamten Pool zu schließen und einen neuen an seiner Stelle zu erstellen.

method sqlalchemy.pool.Pool.status() str

Gibt eine kurze Beschreibung des Zustands dieses Pools zurück.

class sqlalchemy.pool.QueuePool

Ein Pool, der die Anzahl der offenen Verbindungen begrenzt.

QueuePool ist die Standard-Pooling-Implementierung für alle Engine-Objekte außer SQLite mit einer :memory:-Datenbank.

Die Klasse QueuePool ist **nicht kompatibel** mit asyncio und create_async_engine(). Die Klasse AsyncAdaptedQueuePool wird automatisch verwendet, wenn create_async_engine() verwendet wird, sofern kein anderer Pool-Typ angegeben ist.

method sqlalchemy.pool.QueuePool.__init__(creator: _CreatorFnType | _CreatorWRecFnType, pool_size: int = 5, max_overflow: int = 10, timeout: float = 30.0, use_lifo: bool = False, **kw: Any)

Konstruiert einen QueuePool.

Parameter:
  • creator – eine aufrufbare Funktion, die ein DB-API-Verbindungsobjekt zurückgibt, wie bei Pool.creator.

  • pool_size – Die Größe des zu pflegenden Pools, standardmäßig 5. Dies ist die maximale Anzahl von Verbindungen, die persistent im Pool gehalten werden. Beachten Sie, dass der Pool mit keinen Verbindungen beginnt; sobald diese Anzahl von Verbindungen angefordert wurde, bleiben diese erhalten. pool_size kann auf 0 gesetzt werden, um keine Größenbeschränkung anzugeben; zur Deaktivierung des Poolings verwenden Sie stattdessen einen NullPool.

  • max_overflow – Die maximale Überlaufgröße des Pools. Wenn die Anzahl der ausgecheckten Verbindungen die in pool_size eingestellte Größe erreicht, werden zusätzliche Verbindungen bis zu diesem Limit zurückgegeben. Wenn diese zusätzlichen Verbindungen an den Pool zurückgegeben werden, werden sie getrennt und verworfen. Daraus folgt, dass die Gesamtzahl der gleichzeitigen Verbindungen, die der Pool zulässt, pool_size + max_overflow beträgt und die Gesamtzahl der "schlafenden" Verbindungen, die der Pool zulässt, pool_size beträgt. max_overflow kann auf -1 gesetzt werden, um kein Überflow-Limit anzuzeigen; es wird keine Begrenzung für die Gesamtzahl der gleichzeitigen Verbindungen geben. Standardmäßig 10.

  • timeout – Die Anzahl der Sekunden, die gewartet wird, bevor die Rückgabe einer Verbindung aufgegeben wird. Standardmäßig 30,0. Dies kann ein Float sein, unterliegt jedoch den Einschränkungen von Python-Zeitfunktionen, die im Bereich von zehn Millisekunden möglicherweise nicht zuverlässig sind.

  • use_lifo

    Verwenden Sie LIFO (Last-In-First-Out) beim Abrufen von Verbindungen anstelle von FIFO (First-In-First-Out). Mit LIFO kann ein serverseitiges Timeout-Schema die Anzahl der Verbindungen reduzieren, die während Perioden geringer Nutzung verwendet werden. Stellen Sie bei der Planung für serverseitige Timeouts sicher, dass eine Wiederaufbereitungs- oder Pre-Ping-Strategie verwendet wird, um abgelaufene Verbindungen ordnungsgemäß zu handhaben.

    Neu in Version 1.3.

  • **kw – Andere Schlüsselwortargumente, einschließlich Pool.recycle, Pool.echo, Pool.reset_on_return und andere, werden an den Pool-Konstruktor übergeben.

method sqlalchemy.pool.QueuePool.dispose() None

Verwirft diesen Pool.

Diese Methode lässt die Möglichkeit offen, dass ausgecheckte Verbindungen offen bleiben, da sie nur Verbindungen betrifft, die im Pool untätig sind.

Siehe auch

Pool.recreate()

method sqlalchemy.pool.QueuePool.recreate() QueuePool

Gibt einen neuen Pool zurück, derselben Klasse wie dieser und konfiguriert mit identischen Erstellungsargumenten.

Diese Methode wird in Verbindung mit dispose() verwendet, um einen gesamten Pool zu schließen und einen neuen an seiner Stelle zu erstellen.

method sqlalchemy.pool.QueuePool.status() str

Gibt eine kurze Beschreibung des Zustands dieses Pools zurück.

class sqlalchemy.pool.AsyncAdaptedQueuePool

Eine asyncio-kompatible Version von QueuePool.

Dieser Pool wird standardmäßig verwendet, wenn AsyncEngine-Engines verwendet werden, die von create_async_engine() generiert wurden. Er verwendet eine asyncio-kompatible Queue-Implementierung, die keine threading.Lock verwendet.

Die Argumente und die Funktionsweise von AsyncAdaptedQueuePool sind ansonsten identisch mit denen von QueuePool.

class sqlalchemy.pool.SingletonThreadPool

Ein Pool, der eine Verbindung pro Thread verwaltet.

Verwaltet eine Verbindung pro Thread und verschiebt eine Verbindung niemals zu einem anderen Thread als dem, in dem sie erstellt wurde.

Warnung

Der SingletonThreadPool ruft .close() für willkürliche Verbindungen auf, die über die Einstellung pool_size hinausgehen, z. B. wenn mehr eindeutige Thread-Identitäten als von pool_size angegeben verwendet werden. Diese Bereinigung ist nicht-deterministisch und berücksichtigt nicht, ob die Verbindungen, die mit diesen Thread-Identitäten verknüpft sind, gerade in Gebrauch sind.

SingletonThreadPool kann in einer zukünftigen Version verbessert werden. Derzeit wird es im Allgemeinen nur für Testszenarien mit einer SQLite-Datenbank vom Typ :memory: verwendet und wird für den Produktionseinsatz nicht empfohlen.

Die Klasse SingletonThreadPool ist nicht kompatibel mit asyncio und create_async_engine().

Optionen sind dieselben wie bei Pool, sowie

Parameter:

pool_size – Die Anzahl der Threads, für die gleichzeitig Verbindungen aufrechterhalten werden sollen. Standardwert: fünf.

SingletonThreadPool wird vom SQLite-Dialekt automatisch verwendet, wenn eine speicherbasierte Datenbank verwendet wird. Siehe SQLite.

method sqlalchemy.pool.SingletonThreadPool.connect() PoolProxiedConnection

Gibt eine DBAPI-Verbindung aus dem Pool zurück.

Die Verbindung ist so instrumentiert, dass beim Aufruf ihrer close()-Methode die Verbindung an den Pool zurückgegeben wird.

method sqlalchemy.pool.SingletonThreadPool.dispose() None

Verwirft diesen Pool.

method sqlalchemy.pool.SingletonThreadPool.recreate() SingletonThreadPool

Gibt einen neuen Pool zurück, derselben Klasse wie dieser und konfiguriert mit identischen Erstellungsargumenten.

Diese Methode wird in Verbindung mit dispose() verwendet, um einen gesamten Pool zu schließen und einen neuen an seiner Stelle zu erstellen.

method sqlalchemy.pool.SingletonThreadPool.status() str

Gibt eine kurze Beschreibung des Zustands dieses Pools zurück.

class sqlalchemy.pool.AssertionPool

Ein Pool, der zu einem bestimmten Zeitpunkt höchstens eine ausgecheckte Verbindung zulässt.

Dies löst eine Ausnahme aus, wenn mehr als eine Verbindung gleichzeitig ausgecheckt wird. Nützlich zum Debuggen von Code, der mehr Verbindungen als gewünscht verwendet.

Die Klasse AssertionPool ist kompatibel mit asyncio und create_async_engine().

method sqlalchemy.pool.AssertionPool.dispose() None

Verwirft diesen Pool.

Diese Methode lässt die Möglichkeit offen, dass ausgecheckte Verbindungen offen bleiben, da sie nur Verbindungen betrifft, die im Pool untätig sind.

Siehe auch

Pool.recreate()

method sqlalchemy.pool.AssertionPool.recreate() AssertionPool

Gibt einen neuen Pool zurück, derselben Klasse wie dieser und konfiguriert mit identischen Erstellungsargumenten.

Diese Methode wird in Verbindung mit dispose() verwendet, um einen gesamten Pool zu schließen und einen neuen an seiner Stelle zu erstellen.

method sqlalchemy.pool.AssertionPool.status() str

Gibt eine kurze Beschreibung des Zustands dieses Pools zurück.

class sqlalchemy.pool.NullPool

Ein Pool, der keine Verbindungen poolt.

Stattdessen wird die zugrunde liegende DB-API-Verbindung für jeden Verbindungsaufruf/Verbindungsabbau buchstäblich geöffnet und geschlossen.

Wiederverbindungsfunktionen wie recycle und Verbindungsinvalidierung werden von dieser Pool-Implementierung nicht unterstützt, da keine Verbindungen persistent gehalten werden.

Die Klasse NullPool ist kompatibel mit asyncio und create_async_engine().

method sqlalchemy.pool.NullPool.dispose() None

Verwirft diesen Pool.

Diese Methode lässt die Möglichkeit offen, dass ausgecheckte Verbindungen offen bleiben, da sie nur Verbindungen betrifft, die im Pool untätig sind.

Siehe auch

Pool.recreate()

method sqlalchemy.pool.NullPool.recreate() NullPool

Gibt einen neuen Pool zurück, derselben Klasse wie dieser und konfiguriert mit identischen Erstellungsargumenten.

Diese Methode wird in Verbindung mit dispose() verwendet, um einen gesamten Pool zu schließen und einen neuen an seiner Stelle zu erstellen.

method sqlalchemy.pool.NullPool.status() str

Gibt eine kurze Beschreibung des Zustands dieses Pools zurück.

class sqlalchemy.pool.StaticPool

Ein Pool mit genau einer Verbindung, die für alle Anfragen verwendet wird.

Wiederverbindungsfunktionen wie recycle und Verbindungsinvalidierung (die auch zur Unterstützung der automatischen Wiederverbindung verwendet wird) werden derzeit nur teilweise unterstützt und liefern möglicherweise keine guten Ergebnisse.

Die Klasse StaticPool ist kompatibel mit asyncio und create_async_engine().

method sqlalchemy.pool.StaticPool.dispose() None

Verwirft diesen Pool.

Diese Methode lässt die Möglichkeit offen, dass ausgecheckte Verbindungen offen bleiben, da sie nur Verbindungen betrifft, die im Pool untätig sind.

Siehe auch

Pool.recreate()

method sqlalchemy.pool.StaticPool.recreate() StaticPool

Gibt einen neuen Pool zurück, derselben Klasse wie dieser und konfiguriert mit identischen Erstellungsargumenten.

Diese Methode wird in Verbindung mit dispose() verwendet, um einen gesamten Pool zu schließen und einen neuen an seiner Stelle zu erstellen.

method sqlalchemy.pool.StaticPool.status() str

Gibt eine kurze Beschreibung des Zustands dieses Pools zurück.

class sqlalchemy.pool.ManagesConnection

Gemeinsame Basis für die beiden Verbindungsmanagement-Schnittstellen PoolProxiedConnection und ConnectionPoolEntry.

Diese beiden Objekte werden typischerweise in der öffentlichen API über die Verbindungs-Pool-Ereignishaken bereitgestellt, die unter PoolEvents dokumentiert sind.

Neu in Version 2.0.

attribute sqlalchemy.pool.ManagesConnection.dbapi_connection: DBAPIConnection | None

Ein Verweis auf die tatsächliche DBAPI-Verbindung, die verfolgt wird.

Dies ist ein PEP 249-konformes Objekt, das für traditionelle synchrone Dialekte von der verwendeten Drittanbieter-DBAPI-Implementierung bereitgestellt wird. Für asyncio-Dialekte ist die Implementierung typischerweise ein Adapterobjekt, das vom SQLAlchemy-Dialekt selbst bereitgestellt wird; das zugrunde liegende asyncio-Objekt ist über das Attribut ManagesConnection.driver_connection verfügbar.

Die Schnittstelle von SQLAlchemy für die DBAPI-Verbindung basiert auf dem Protokollobjekt DBAPIConnection

attribute sqlalchemy.pool.ManagesConnection.driver_connection: Any | None

Das "Treiber-Level"-Verbindungsobjekt, wie es von der Python DBAPI oder dem Datenbanktreiber verwendet wird.

Für traditionelle PEP 249-DBAPI-Implementierungen ist dieses Objekt dasselbe wie das von ManagesConnection.dbapi_connection. Für einen asyncio-Datenbanktreiber ist dies das ultimative "Verbindungsobjekt", das von diesem Treiber verwendet wird, wie z. B. das asyncpg.Connection-Objekt, das keine Standard-PEP-249-Methoden hat.

Neu in Version 1.4.24.

attribute sqlalchemy.pool.ManagesConnection.info

Informationswörterbuch, das der zugrunde liegenden DBAPI-Verbindung zugeordnet ist, auf die diese ManagesConnection-Instanz verweist und die Zuordnung benutzerdefinierter Daten zur Verbindung ermöglicht.

Die Daten in diesem Wörterbuch sind für die Lebensdauer der DBAPI-Verbindung selbst persistent, einschließlich über Pool-Check-Ins und Check-Outs hinweg. Wenn die Verbindung ungültig gemacht und durch eine neue ersetzt wird, wird dieses Wörterbuch gelöscht.

Für eine PoolProxiedConnection-Instanz, die nicht mit einem ConnectionPoolEntry verbunden ist, z. B. wenn sie getrennt wurde, gibt das Attribut ein Wörterbuch zurück, das lokal zu diesem ConnectionPoolEntry ist. Daher stellt das Attribut ManagesConnection.info immer ein Python-Wörterbuch bereit.

method sqlalchemy.pool.ManagesConnection.invalidate(e: BaseException | None = None, soft: bool = False) None

Markiert die verwaltete Verbindung als ungültig.

Parameter:
  • e – ein Ausnahmeobjekt, das einen Grund für die Ungültigmachung angibt.

  • soft – wenn True, wird die Verbindung nicht geschlossen; stattdessen wird diese Verbindung beim nächsten Auschecken wiederverwendet.

Attribut sqlalchemy.pool.ManagesConnection.record_info

Persistentes Info-Dictionary, das dieser ManagesConnection zugeordnet ist.

Im Gegensatz zum ManagesConnection.info-Dictionary ist die Lebensdauer dieses Dictionaries an die des ConnectionPoolEntry gebunden, dem es gehört; daher bleibt dieses Dictionary über Wiederverbindungen und ungültige Verbindungen für einen bestimmten Eintrag im Connection-Pool hinweg bestehen.

Für eine PoolProxiedConnection-Instanz, die keinem ConnectionPoolEntry zugeordnet ist, z. B. wenn sie getrennt wurde, gibt das Attribut None zurück. Im Gegensatz zum ManagesConnection.info-Dictionary, das niemals None ist.

Klasse sqlalchemy.pool.ConnectionPoolEntry

Schnittstelle für das Objekt, das eine einzelne Datenbankverbindung im Auftrag einer Pool-Instanz verwaltet.

Das Objekt ConnectionPoolEntry repräsentiert die langfristige Wartung einer bestimmten Verbindung für einen Pool, einschließlich des Ablaufs oder der Ungültigmachung dieser Verbindung, damit sie durch eine neue ersetzt wird, die weiterhin von derselben ConnectionPoolEntry-Instanz verwaltet wird. Verglichen mit PoolProxiedConnection, dem kurzfristigen Verbindungsmanager pro Ausleihe, existiert dieses Objekt für die Lebensdauer eines bestimmten „Slots“ innerhalb eines Connection-Pools.

Das Objekt ConnectionPoolEntry ist für öffentlich zugänglichen API-Code hauptsächlich sichtbar, wenn es an Hook für Pool-Events geliefert wird, wie z. B. PoolEvents.connect() und PoolEvents.checkout().

Neu in Version 2.0: ConnectionPoolEntry bietet die öffentliche Schnittstelle für die interne Klasse _ConnectionRecord.

Methode sqlalchemy.pool.ConnectionPoolEntry.close() None

Schließt die von diesem Connection-Pool-Eintrag verwaltete DBAPI-Verbindung.

Attribut sqlalchemy.pool.ConnectionPoolEntry.dbapi_connection: DBAPIConnection | None

Ein Verweis auf die tatsächliche DBAPI-Verbindung, die verfolgt wird.

Dies ist ein PEP 249-konformes Objekt, das für traditionelle synchrone Dialekte von der Drittanbieter-DBAPI-Implementierung bereitgestellt wird. Für asynchrone Dialekte ist die Implementierung typischerweise ein Adapterobjekt, das vom SQLAlchemy-Dialekt selbst bereitgestellt wird; das zugrundeliegende asynchrone Objekt ist über das Attribut ManagesConnection.driver_connection verfügbar.

Die Schnittstelle von SQLAlchemy für die DBAPI-Verbindung basiert auf dem Protokollobjekt DBAPIConnection

Attribut sqlalchemy.pool.ConnectionPoolEntry.driver_connection: Any | None

Das "Treiber-Level"-Verbindungsobjekt, wie es von der Python DBAPI oder dem Datenbanktreiber verwendet wird.

Für traditionelle PEP 249-DBAPI-Implementierungen ist dieses Objekt dasselbe Objekt wie ManagesConnection.dbapi_connection. Für einen asynchronen Datenbanktreiber ist dies das ultimative „Verbindungsobjekt“, das von diesem Treiber verwendet wird, z. B. das asyncpg.Connection-Objekt, das keine Standard-PEP-249-Methoden hat.

Neu in Version 1.4.24.

Attribut sqlalchemy.pool.ConnectionPoolEntry.in_use

Gibt True zurück, wenn die Verbindung derzeit ausgeliehen ist.

Attribut sqlalchemy.pool.ConnectionPoolEntry.info

geerbt vom ManagesConnection.info Attribut von ManagesConnection

Informationswörterbuch, das der zugrunde liegenden DBAPI-Verbindung zugeordnet ist, auf die diese ManagesConnection-Instanz verweist und die Zuordnung benutzerdefinierter Daten zur Verbindung ermöglicht.

Die Daten in diesem Wörterbuch sind für die Lebensdauer der DBAPI-Verbindung selbst persistent, einschließlich über Pool-Check-Ins und Check-Outs hinweg. Wenn die Verbindung ungültig gemacht und durch eine neue ersetzt wird, wird dieses Wörterbuch gelöscht.

Für eine PoolProxiedConnection-Instanz, die nicht mit einem ConnectionPoolEntry verbunden ist, z. B. wenn sie getrennt wurde, gibt das Attribut ein Wörterbuch zurück, das lokal zu diesem ConnectionPoolEntry ist. Daher stellt das Attribut ManagesConnection.info immer ein Python-Wörterbuch bereit.

Methode sqlalchemy.pool.ConnectionPoolEntry.invalidate(e: BaseException | None = None, soft: bool = False) None

geerbt von der ManagesConnection.invalidate() Methode von ManagesConnection

Markiert die verwaltete Verbindung als ungültig.

Parameter:
  • e – Ein Ausnahmeobjekt, das einen Grund für die Ungültigmachung angibt.

  • soft – Wenn True, wird die Verbindung nicht geschlossen; stattdessen wird diese Verbindung beim nächsten Ausleihen wiederverwendet.

Attribut sqlalchemy.pool.ConnectionPoolEntry.record_info

geerbt vom ManagesConnection.record_info Attribut von ManagesConnection

Persistentes Info-Dictionary, das dieser ManagesConnection zugeordnet ist.

Im Gegensatz zum ManagesConnection.info-Dictionary ist die Lebensdauer dieses Dictionaries an die des ConnectionPoolEntry gebunden, dem es gehört; daher bleibt dieses Dictionary über Wiederverbindungen und ungültige Verbindungen für einen bestimmten Eintrag im Connection-Pool hinweg bestehen.

Für eine PoolProxiedConnection-Instanz, die keinem ConnectionPoolEntry zugeordnet ist, z. B. wenn sie getrennt wurde, gibt das Attribut None zurück. Im Gegensatz zum ManagesConnection.info-Dictionary, das niemals None ist.

Klasse sqlalchemy.pool.PoolProxiedConnection

Ein Connection-Adapter, der einer PEP 249 DBAPI-Verbindung ähnelt und zusätzliche Methoden enthält, die für die Pool-Implementierung spezifisch sind.

PoolProxiedConnection ist die öffentliche Schnittstelle für das interne Implementierungsobjekt _ConnectionFairy; Benutzer, die mit _ConnectionFairy vertraut sind, können dieses Objekt als gleichwertig betrachten.

Neu in Version 2.0: PoolProxiedConnection bietet die öffentliche Schnittstelle für die interne Klasse _ConnectionFairy.

Methode sqlalchemy.pool.PoolProxiedConnection.close() None

Gibt diese Verbindung an den Pool zurück.

Die Methode PoolProxiedConnection.close() überschattet die PEP 249 .close()-Methode und ändert ihr Verhalten dahingehend, dass die proxy-gesteuerte Verbindung stattdessen an den Connection-Pool freigegeben wird.

Nach der Freigabe an den Pool hängt es von der verwendeten Pool-Implementierung und deren Konfiguration und aktuellem Zustand ab, ob die Verbindung im Python-Prozess „geöffnet“ und gepoolt bleibt oder tatsächlich geschlossen und aus dem Python-Prozess entfernt wird.

Attribut sqlalchemy.pool.PoolProxiedConnection.dbapi_connection: DBAPIConnection | None

Ein Verweis auf die tatsächliche DBAPI-Verbindung, die verfolgt wird.

Dies ist ein PEP 249-konformes Objekt, das für traditionelle synchrone Dialekte von der Drittanbieter-DBAPI-Implementierung bereitgestellt wird. Für asynchrone Dialekte ist die Implementierung typischerweise ein Adapterobjekt, das vom SQLAlchemy-Dialekt selbst bereitgestellt wird; das zugrundeliegende asynchrone Objekt ist über das Attribut ManagesConnection.driver_connection verfügbar.

Die Schnittstelle von SQLAlchemy für die DBAPI-Verbindung basiert auf dem Protokollobjekt DBAPIConnection

Methode sqlalchemy.pool.PoolProxiedConnection.detach() None

Trennt diese Verbindung von ihrem Pool.

Dies bedeutet, dass die Verbindung beim Schließen nicht mehr an den Pool zurückgegeben, sondern stattdessen buchstäblich geschlossen wird. Der zugehörige ConnectionPoolEntry wird von dieser DBAPI-Verbindung getrennt.

Beachten Sie, dass alle vom Pool implementierten Verbindungslimitierungsbeschränkungen nach dem Trennen verletzt werden können, da die getrennte Verbindung aus der Kenntnis und Kontrolle des Pools entfernt wird.

Attribut sqlalchemy.pool.PoolProxiedConnection.driver_connection: Any | None

Das "Treiber-Level"-Verbindungsobjekt, wie es von der Python DBAPI oder dem Datenbanktreiber verwendet wird.

Für traditionelle PEP 249-DBAPI-Implementierungen ist dieses Objekt dasselbe Objekt wie ManagesConnection.dbapi_connection. Für einen asynchronen Datenbanktreiber ist dies das ultimative „Verbindungsobjekt“, das von diesem Treiber verwendet wird, z. B. das asyncpg.Connection-Objekt, das keine Standard-PEP-249-Methoden hat.

Neu in Version 1.4.24.

Attribut sqlalchemy.pool.PoolProxiedConnection.info

geerbt vom ManagesConnection.info Attribut von ManagesConnection

Informationswörterbuch, das der zugrunde liegenden DBAPI-Verbindung zugeordnet ist, auf die diese ManagesConnection-Instanz verweist und die Zuordnung benutzerdefinierter Daten zur Verbindung ermöglicht.

Die Daten in diesem Wörterbuch sind für die Lebensdauer der DBAPI-Verbindung selbst persistent, einschließlich über Pool-Check-Ins und Check-Outs hinweg. Wenn die Verbindung ungültig gemacht und durch eine neue ersetzt wird, wird dieses Wörterbuch gelöscht.

Für eine PoolProxiedConnection-Instanz, die nicht mit einem ConnectionPoolEntry verbunden ist, z. B. wenn sie getrennt wurde, gibt das Attribut ein Wörterbuch zurück, das lokal zu diesem ConnectionPoolEntry ist. Daher stellt das Attribut ManagesConnection.info immer ein Python-Wörterbuch bereit.

Methode sqlalchemy.pool.PoolProxiedConnection.invalidate(e: BaseException | None = None, soft: bool = False) None

geerbt von der ManagesConnection.invalidate() Methode von ManagesConnection

Markiert die verwaltete Verbindung als ungültig.

Parameter:
  • e – Ein Ausnahmeobjekt, das einen Grund für die Ungültigmachung angibt.

  • soft – Wenn True, wird die Verbindung nicht geschlossen; stattdessen wird diese Verbindung beim nächsten Ausleihen wiederverwendet.

Attribut sqlalchemy.pool.PoolProxiedConnection.is_detached

Gibt True zurück, wenn diese PoolProxiedConnection von ihrem Pool getrennt ist.

Attribut sqlalchemy.pool.PoolProxiedConnection.is_valid

Gibt True zurück, wenn diese PoolProxiedConnection immer noch auf eine aktive DBAPI-Verbindung verweist.

Attribut sqlalchemy.pool.PoolProxiedConnection.record_info

geerbt vom ManagesConnection.record_info Attribut von ManagesConnection

Persistentes Info-Dictionary, das dieser ManagesConnection zugeordnet ist.

Im Gegensatz zum ManagesConnection.info-Dictionary ist die Lebensdauer dieses Dictionaries an die des ConnectionPoolEntry gebunden, dem es gehört; daher bleibt dieses Dictionary über Wiederverbindungen und ungültige Verbindungen für einen bestimmten Eintrag im Connection-Pool hinweg bestehen.

Für eine PoolProxiedConnection-Instanz, die keinem ConnectionPoolEntry zugeordnet ist, z. B. wenn sie getrennt wurde, gibt das Attribut None zurück. Im Gegensatz zum ManagesConnection.info-Dictionary, das niemals None ist.

Klasse sqlalchemy.pool._ConnectionFairy

Proxy für eine DBAPI-Verbindung, die Rückgabe bei Dereferenzierung unterstützt.

Dies ist ein internes Objekt, das von der Pool-Implementierung verwendet wird, um die Kontextverwaltung für eine von diesem Pool bereitgestellte DBAPI-Verbindung zu ermöglichen. Die öffentliche Schnittstelle für diese Klasse wird durch die Klasse PoolProxiedConnection beschrieben. Siehe diese Klasse für Details zur öffentlichen API.

Der Name „Fairy“ (Fee) ist inspiriert von der Tatsache, dass die Lebensdauer des Objekts _ConnectionFairy vergänglich ist, da es nur für die Dauer einer bestimmten von einem Pool ausgeliehenen DBAPI-Verbindung besteht, und dass es als transparenter Proxy größtenteils unsichtbar ist.

Klassensignatur

class sqlalchemy.pool._ConnectionFairy (sqlalchemy.pool.base.PoolProxiedConnection)

Klasse sqlalchemy.pool._ConnectionRecord

Führt eine Position in einem Connection-Pool, die eine gepoolte Verbindung referenziert.

Dies ist ein internes Objekt, das von der Pool-Implementierung verwendet wird, um die Kontextverwaltung für eine von diesem Pool verwaltete DBAPI-Verbindung zu ermöglichen. Die öffentliche Schnittstelle für diese Klasse wird durch die Klasse ConnectionPoolEntry beschrieben. Siehe diese Klasse für Details zur öffentlichen API.

Klassensignatur

class sqlalchemy.pool._ConnectionRecord (sqlalchemy.pool.base.ConnectionPoolEntry)