SQLAlchemy 2.0 Dokumentation
Häufig gestellte Fragen
- Installation
- Verbindungen / Engines¶
- Wie konfiguriere ich Logging?
- Wie poolle ich Datenbankverbindungen? Werden meine Verbindungen gepoolt?
- Wie übergibe ich benutzerdefinierte Verbindungsargumente an meine Datenbank-API?
- „MySQL Server hat sich verabschiedet“
- „Befehle nicht synchron; Sie können diesen Befehl jetzt nicht ausführen“ / „Dieses Ergebnisobjekt gibt keine Zeilen zurück. Es wurde automatisch geschlossen“
- Wie kann ich die Ausführung einer Anweisung automatisch „wiederholen“?
- Warum gibt SQLAlchemy so viele ROLLBACKs aus?
- Ich verwende mehrere Verbindungen mit einer SQLite-Datenbank (typischerweise zum Testen von Transaktionsoperationen) und mein Testprogramm funktioniert nicht!
- Wie bekomme ich die rohe DBAPI-Verbindung, wenn ich eine Engine verwende?
- Wie verwende ich Engines / Verbindungen / Sitzungen mit Python-Multiprocessing oder os.fork()?
- MetaData / Schema
- SQL-Ausdrücke
- ORM-Konfiguration
- Performance
- Sessions / Abfragen
- Probleme bei der Integration von Drittanbietern
Projektversionen
- Vorher: Installation
- Nächste: MetaData / Schema
- Nach oben: Startseite
- Auf dieser Seite
- Verbindungen / Engines
- Wie konfiguriere ich Logging?
- Wie poolle ich Datenbankverbindungen? Werden meine Verbindungen gepoolt?
- Wie übergibe ich benutzerdefinierte Verbindungsargumente an meine Datenbank-API?
- „MySQL Server hat sich verabschiedet“
- „Befehle nicht synchron; Sie können diesen Befehl jetzt nicht ausführen“ / „Dieses Ergebnisobjekt gibt keine Zeilen zurück. Es wurde automatisch geschlossen“
- Wie kann ich die Ausführung einer Anweisung automatisch „wiederholen“?
- Warum gibt SQLAlchemy so viele ROLLBACKs aus?
- Ich verwende mehrere Verbindungen mit einer SQLite-Datenbank (typischerweise zum Testen von Transaktionsoperationen) und mein Testprogramm funktioniert nicht!
- Wie bekomme ich die rohe DBAPI-Verbindung, wenn ich eine Engine verwende?
- Wie verwende ich Engines / Verbindungen / Sitzungen mit Python-Multiprocessing oder os.fork()?
Verbindungen / Engines¶
Wie konfiguriere ich Logging?¶
Siehe Konfiguration von Logging.
Wie poolle ich Datenbankverbindungen? Werden meine Verbindungen gepoolt?¶
SQLAlchemy führt in den meisten Fällen automatisch ein Application-Level-Verbindungs-Pooling durch. Für alle enthaltenen Dialekte (außer SQLite bei Verwendung einer „memory“-Datenbank) verweist ein Engine-Objekt auf einen QueuePool als Quelle der Konnektivität.
Weitere Details finden Sie unter Engine-Konfiguration und Verbindungs-Pooling.
Wie übergibe ich benutzerdefinierte Verbindungsargumente an meine Datenbank-API?¶
Der Aufruf create_engine() akzeptiert zusätzliche Argumente entweder direkt über das Schlüsselwortargument connect_args
e = create_engine(
"mysql+mysqldb://scott:tiger@localhost/test", connect_args={"encoding": "utf8"}
)Oder für einfache Zeichenketten- und Ganzzahlargumente können diese normalerweise in der Abfragestruktur der URL angegeben werden
e = create_engine("mysql+mysqldb://scott:tiger@localhost/test?encoding=utf8")„MySQL Server hat sich verabschiedet“¶
Die Hauptursache für diesen Fehler ist, dass die MySQL-Verbindung abgelaufen ist und vom Server geschlossen wurde. Der MySQL-Server schließt Verbindungen, die eine Zeit lang inaktiv waren, standardmäßig acht Stunden. Um dem Rechnung zu tragen, ist die sofortige Einstellung die Aktivierung der create_engine.pool_recycle-Einstellung, die sicherstellt, dass eine Verbindung, die älter als eine festgelegte Anzahl von Sekunden ist, verworfen und durch eine neue Verbindung ersetzt wird, wenn sie das nächste Mal abgerufen wird.
Für den allgemeineren Fall der Berücksichtigung von Datenbankneustarts und anderen vorübergehenden Verlusten der Konnektivität aufgrund von Netzwerkproblemen können Verbindungen, die sich im Pool befinden, als Reaktion auf allgemeinere Erkennungstechniken für Verbindungsabbrüche recycelt werden. Der Abschnitt Umgang mit Verbindungsabbrüchen bietet Hintergrundinformationen zu „pessimistischen“ (z. B. Pre-Ping) und „optimistischen“ (z. B. sanfter Wiederherstellung) Techniken. Modernes SQLAlchemy tendiert dazu, den „pessimistischen“ Ansatz zu bevorzugen.
Siehe auch
„Befehle nicht synchron; Sie können diesen Befehl jetzt nicht ausführen“ / „Dieses Ergebnisobjekt gibt keine Zeilen zurück. Es wurde automatisch geschlossen“¶
Die MySQL-Treiber haben eine ziemlich große Klasse von Fehlermodi, bei denen der Zustand der Verbindung zum Server ungültig ist. Typischerweise, wenn die Verbindung erneut verwendet wird, tritt eine dieser beiden Fehlermeldungen auf. Der Grund dafür ist, dass der Zustand des Servers in einen Zustand geändert wurde, den die Clientbibliothek nicht erwartet, so dass, wenn die Clientbibliothek eine neue Anweisung über die Verbindung ausgibt, der Server nicht wie erwartet antwortet.
In SQLAlchemy ist, da Datenbankverbindungen gepoolt werden, das Problem der nicht synchronen Nachrichten über eine Verbindung wichtiger. Wenn eine Operation fehlschlägt und die Verbindung selbst in einem unbrauchbaren Zustand ist, wird sie, wenn sie zurück in den Verbindungspool gelangt, bei erneutem Abruf fehlerhaft funktionieren. Die Abhilfe für dieses Problem besteht darin, dass die Verbindung bei einem solchen Fehlerzustand als **ungültig markiert** wird, damit die zugrunde liegende Datenbankverbindung zu MySQL verworfen wird. Diese Ungültigkeitserklärung erfolgt automatisch für viele bekannte Fehlerzustände und kann auch explizit über die Methode Connection.invalidate() aufgerufen werden.
Es gibt auch eine zweite Klasse von Fehlermodi in dieser Kategorie, bei der ein Kontextmanager wie with session.begin_nested(): bei einem Fehler die Transaktion „zurücksetzen“ möchte; jedoch schlägt bei einigen Fehlerzuständen der Verbindung auch das Zurücksetzen selbst (was auch eine RELEASE SAVEPOINT-Operation sein kann) fehl, was zu irreführenden Stack-Traces führt.
Ursprünglich war die Ursache dieses Fehlers recht einfach: Er bedeutete, dass ein Multithreading-Programm Befehle von mehr als einem Thread über eine einzelne Verbindung aufrief. Dies galt für den ursprünglichen nativen C-Treiber „MySQLdb“, der so gut wie der einzige verwendete Treiber war. Mit der Einführung von reinen Python-Treibern wie PyMySQL und MySQL-connector-Python sowie der zunehmenden Nutzung von Tools wie gevent/eventlet, Multiprocessing (oft mit Celery) und anderen gibt es eine ganze Reihe von Faktoren, die bekanntermaßen dieses Problem verursachen, von denen einige in SQLAlchemy-Versionen verbessert wurden, andere jedoch unvermeidlich sind.
Gemeinsame Nutzung einer Verbindung zwischen Threads – Dies ist der ursprüngliche Grund, warum diese Art von Fehlern auftrat. Ein Programm verwendete dieselbe Verbindung gleichzeitig in zwei oder mehr Threads, was bedeutet, dass mehrere Nachrichtensätze auf der Verbindung vermischt wurden und die serverseitige Sitzung in einen Zustand geriet, den der Client nicht mehr interpretieren konnte. Heutzutage sind jedoch andere Ursachen wahrscheinlicher.
Gemeinsame Nutzung des Filehandles der Verbindung zwischen Prozessen – Dies geschieht normalerweise, wenn ein Programm Python’s „multiprocessing“-Modul verwendet und einen
Engineverwendet, der im übergeordneten Prozess erstellt wurde und in einen oder mehrere untergeordnete Prozesse weitergegeben wird. Da mehrere Prozesse nun im Wesentlichen auf dasselbe Filehandle zugreifen, empfängt der Server verschachtelte Nachrichten und bricht den Zustand der Verbindung ab.Dieses Szenario kann sehr leicht auftreten, wenn ein Programm das „multiprocessing“-Modul von Python verwendet und einen
Engineverwendet, der im übergeordneten Prozess erstellt wurde. Es ist üblich, dass „multiprocessing“ verwendet wird, wenn Tools wie Celery verwendet werden. Der richtige Ansatz sollte entweder sein, dass ein neuerEngineerstellt wird, wenn ein untergeordneter Prozess zuerst gestartet wird, und alle von übergeordneten Prozessen stammendenEngineverworfen werden; oder der vom übergeordneten Prozess geerbteEnginekann seinen internen Verbindungspool entleeren, indem die MethodeEngine.dispose()aufgerufen wird.Greenlet Monkeypatching mit Exits – Bei der Verwendung von Bibliotheken wie gevent oder eventlet, die die Python-Netzwerk-API monkeypatchen, arbeiten Bibliotheken wie PyMySQL jetzt in einem asynchronen Betriebsmodus, obwohl sie nicht explizit gegen dieses Modell entwickelt wurden. Ein häufiges Problem ist, dass ein Greenthread unterbrochen wird, oft aufgrund von Timeout-Logik in der Anwendung. Dies führt dazu, dass die Ausnahme
GreenletExitausgelöst wird, und der reine Python-MySQL-Treiber wird von seiner Arbeit unterbrochen, was möglicherweise der Empfang einer Antwort vom Server oder die Vorbereitung zur Rücksetzung des Verbindungsstatus war. Wenn die Ausnahme all diese Arbeiten verkürzt, ist die Konversation zwischen Client und Server nun nicht mehr synchron und die anschließende Nutzung der Verbindung kann fehlschlagen. SQLAlchemy weiß seit Version 1.1.0, wie es dagegen absichert, da, wenn eine Datenbankoperation durch eine sogenannte „Exit-Ausnahme“ unterbrochen wird, dieGreenletExitund jede andere Unterklasse von PythonBaseException, die keine Unterklasse vonExceptionist, die Verbindung ungültig gemacht wird.Rollbacks / SAVEPOINT-Freigaben schlagen fehl – Einige Fehlerklassen machen die Verbindung im Kontext einer Transaktion sowie bei der Arbeit in einem „SAVEPOINT“-Block unbrauchbar. In diesen Fällen hat der Fehler an der Verbindung dazu geführt, dass kein SAVEPOINT mehr existiert, aber wenn SQLAlchemy oder die Anwendung versucht, diesen Savepoint „zurückzusetzen“, schlägt die Operation „RELEASE SAVEPOINT“ fehl, typischerweise mit einer Meldung wie „savepoint does not exist“. In diesem Fall wird unter Python 3 eine Kette von Ausnahmen ausgegeben, wobei die ultimative „Ursache“ des Fehlers ebenfalls angezeigt wird. Unter Python 2 gibt es keine „verketteten“ Ausnahmen. Neuere Versionen von SQLAlchemy versuchen jedoch, eine Warnung auszugeben, die die ursprüngliche Fehlerursache veranschaulicht, während sie immer noch den unmittelbaren Fehler auslöst, der das Fehlschlagen des ROLLBACK ist.
Wie kann ich die Ausführung einer Anweisung automatisch „wiederholen“?¶
Der Dokumentationsabschnitt Umgang mit Verbindungsabbrüchen erörtert die verfügbaren Strategien für gepoolte Verbindungen, die seit dem letzten Abruf einer bestimmten Verbindung getrennt wurden. Das modernste Feature in dieser Hinsicht ist der Parameter create_engine.pre_ping, der es ermöglicht, einen „Ping“ an eine Datenbankverbindung zu senden, wenn sie aus dem Pool abgerufen wird, und sich neu zu verbinden, wenn die aktuelle Verbindung getrennt wurde.
Es ist wichtig zu beachten, dass dieser „Ping“ nur **vor** der tatsächlichen Verwendung der Verbindung für eine Operation gesendet wird. Sobald die Verbindung an den Aufrufer geliefert wird, unterliegt sie gemäß der Python DBAPI-Spezifikation einer **autobegin**-Operation, was bedeutet, dass sie automatisch eine neue Transaktion beginnt, wenn sie zum ersten Mal verwendet wird, die für nachfolgende Anweisungen in Kraft bleibt, bis die connection.commit() oder connection.rollback() Methode auf DBAPI-Ebene aufgerufen wird.
Im modernen Gebrauch von SQLAlchemy werden eine Reihe von SQL-Anweisungen immer innerhalb dieses Transaktionszustands ausgeführt, vorausgesetzt, DBAPI Autocommit-Modus ist nicht aktiviert (mehr dazu im nächsten Abschnitt), was bedeutet, dass keine einzelne Anweisung automatisch committet wird; wenn eine Operation fehlschlägt, gehen die Auswirkungen aller Anweisungen innerhalb der aktuellen Transaktion verloren.
Die Implikation für die Vorstellung des „Wiederholens“ einer Anweisung ist, dass im Standardfall, wenn eine Verbindung verloren geht, **die gesamte Transaktion verloren geht**. Es gibt keine sinnvolle Möglichkeit, dass die Datenbank sich „wiederverbinden und wiederholen“ und dort fortfahren kann, wo sie aufgehört hat, da Daten bereits verloren sind. Aus diesem Grund hat SQLAlchemy keine transparente „Wiederverbindungsfunktion“, die mitten in einer Transaktion funktioniert, wenn die Datenbankverbindung während der Verwendung unterbrochen wurde. Der kanonische Ansatz für den Umgang mit Unterbrechungen während einer Operation ist, **die gesamte Operation vom Beginn der Transaktion an neu zu versuchen**, oft durch die Verwendung eines benutzerdefinierten Python-Dekorators, der eine bestimmte Funktion mehrmals „wiederholt“, bis sie erfolgreich ist, oder die Anwendung anderweitig so zu gestalten, dass sie widerstandsfähig gegen Transaktionen ist, die abgebrochen werden und dann zu fehlgeschlagenen Operationen führen.
Es gibt auch die Vorstellung von Erweiterungen, die alle Anweisungen, die innerhalb einer Transaktion ausgeführt wurden, verfolgen und dann alle in einer neuen Transaktion erneut abspielen können, um eine „Wiederholung“-Operation zu approximieren. Das Ereignissystem von SQLAlchemy ermöglicht den Aufbau eines solchen Systems, dieser Ansatz ist jedoch auch nicht allgemein nützlich, da es keine Möglichkeit gibt zu garantieren, dass diese DML-Anweisungen mit demselben Zustand arbeiten, da nach Beendigung einer Transaktion der Zustand der Datenbank in einer neuen Transaktion völlig anders sein kann. Das explizite Einbauen von „Retry“ in die Anwendung an den Stellen, an denen Transaktionsoperationen beginnen und committet werden, bleibt der bessere Ansatz, da die anwendungsbezogenen Transaktionsmethoden am besten wissen, wie ihre Schritte wiederholt werden.
Wenn SQLAlchemy ansonsten eine Funktion bereitstellen würde, die eine Verbindung mitten in einer Transaktion transparent und stillschweigend „wiederverbindet“, wäre die Auswirkung, dass Daten stillschweigend verloren gehen. Indem SQLAlchemy versuchen würde, das Problem zu verbergen, würde es die Situation viel schlimmer machen.
Wenn wir jedoch **keine** Transaktionen verwenden, dann gibt es mehr Optionen, wie der nächste Abschnitt beschreibt.
Die Verwendung von DBAPI Autocommit ermöglicht eine schreibgeschützte Version von transparentem Wiederverbinden¶
Mit der Begründung für das Fehlen eines transparenten Wiederverbindungsmechanismus beruht der vorherige Abschnitt auf der Annahme, dass die Anwendung tatsächlich DBAPI-Transaktionen verwendet. Da die meisten DBAPIs mittlerweile native „Autocommit“-Einstellungen anbieten, können wir diese Funktionen nutzen, um eine begrenzte Form des transparenten Wiederverbindens für **schreibgeschützte, nur-autocommit-Operationen** bereitzustellen. Eine transparente Anweisungsretry kann auf die Methode cursor.execute() des DBAPI angewendet werden, es ist jedoch immer noch nicht sicher, sie auf die Methode cursor.executemany() des DBAPI anzuwenden, da die Anweisung einen Teil der übergebenen Argumente verbraucht haben kann.
Warnung
Das folgende Rezept sollte **nicht** für Operationen verwendet werden, die Daten schreiben. Benutzer sollten sorgfältig lesen und verstehen, wie das Rezept funktioniert, und Fehlerzustände sehr sorgfältig gegen den spezifisch anvisierten DBAPI-Treiber testen, bevor sie dieses Rezept produktiv einsetzen. Der Retry-Mechanismus garantiert nicht in allen Fällen die Verhinderung von Verbindungsfehlern.
Ein einfacher Retry-Mechanismus kann auf die cursor.execute()-Methode auf DBAPI-Ebene angewendet werden, indem die Hooks DialectEvents.do_execute() und DialectEvents.do_execute_no_params() verwendet werden, die Verbindungsabbrüche während der Anweisungsausführung abfangen können. Sie fängt **keine** Verbindungsfehler während der Abruffunktionen von Ergebnisdatensätzen ab, für die DBAPIs keine vollständige Pufferung von Ergebnisdatensätzen durchführen. Das Rezept erfordert, dass die Datenbank DBAPI-Level-Autocommit unterstützt und ist für bestimmte Backends **nicht garantiert**. Eine einzelne Funktion reconnecting_engine() wird präsentiert, die die Event-Hooks auf ein gegebenes Engine-Objekt anwendet und eine immer-autocommit-Version zurückgibt, die DBAPI-Level-Autocommit aktiviert. Eine Verbindung wird für Anweisungsausführungen mit einzelnen oder keinen Parametern transparent wiederhergestellt.
import time
from sqlalchemy import event
def reconnecting_engine(engine, num_retries, retry_interval):
def _run_with_retries(fn, context, cursor_obj, statement, *arg, **kw):
for retry in range(num_retries + 1):
try:
fn(cursor_obj, statement, context=context, *arg)
except engine.dialect.dbapi.Error as raw_dbapi_err:
connection = context.root_connection
if engine.dialect.is_disconnect(raw_dbapi_err, connection, cursor_obj):
engine.logger.error(
"disconnection error, attempt %d/%d",
retry + 1,
num_retries + 1,
exc_info=True,
)
connection.invalidate()
# use SQLAlchemy 2.0 API if available
if hasattr(connection, "rollback"):
connection.rollback()
else:
trans = connection.get_transaction()
if trans:
trans.rollback()
if retry == num_retries:
raise
time.sleep(retry_interval)
context.cursor = cursor_obj = connection.connection.cursor()
else:
raise
else:
return True
e = engine.execution_options(isolation_level="AUTOCOMMIT")
@event.listens_for(e, "do_execute_no_params")
def do_execute_no_params(cursor_obj, statement, context):
return _run_with_retries(
context.dialect.do_execute_no_params, context, cursor_obj, statement
)
@event.listens_for(e, "do_execute")
def do_execute(cursor_obj, statement, parameters, context):
return _run_with_retries(
context.dialect.do_execute, context, cursor_obj, statement, parameters
)
return eMit dem obigen Rezept kann ein Wiederverbindungsversuch mitten in einer Transaktion anhand des folgenden Proof-of-Concept-Skripts demonstriert werden. Nach dem Ausführen sendet es alle fünf Sekunden eine SELECT 1-Anweisung an die Datenbank.
from sqlalchemy import create_engine
from sqlalchemy import select
if __name__ == "__main__":
engine = create_engine("mysql+mysqldb://scott:tiger@localhost/test", echo_pool=True)
def do_a_thing(engine):
with engine.begin() as conn:
while True:
print("ping: %s" % conn.execute(select([1])).scalar())
time.sleep(5)
e = reconnecting_engine(
create_engine("mysql+mysqldb://scott:tiger@localhost/test", echo_pool=True),
num_retries=5,
retry_interval=2,
)
do_a_thing(e)Starten Sie die Datenbank neu, während das Skript läuft, um den transparenten Wiederverbindungsbetrieb zu demonstrieren.
$ python reconnect_test.py
ping: 1
ping: 1
disconnection error, retrying operation
Traceback (most recent call last):
...
MySQLdb._exceptions.OperationalError: (2006, 'MySQL server has gone away')
2020-10-19 16:16:22,624 INFO sqlalchemy.pool.impl.QueuePool Invalidate connection <_mysql.connection open to 'localhost' at 0xf59240>
ping: 1
ping: 1
...Das obige Rezept wurde für SQLAlchemy 1.4 getestet.
Warum gibt SQLAlchemy so viele ROLLBACKs aus?¶
SQLAlchemy geht derzeit davon aus, dass DBAPI-Verbindungen im „Nicht-Autocommit“-Modus sind – dies ist das Standardverhalten der Python-Datenbank-API, was bedeutet, dass angenommen werden muss, dass immer eine Transaktion läuft. Der Verbindungspool gibt connection.rollback() aus, wenn eine Verbindung zurückgegeben wird. Dies geschieht, damit alle verbleibenden Transaktionsressourcen auf der Verbindung freigegeben werden. Auf einer Datenbank wie PostgreSQL oder MSSQL, wo Tabellenressourcen aggressiv gesperrt werden, ist dies entscheidend, damit Zeilen und Tabellen in Verbindungen, die nicht mehr verwendet werden, nicht gesperrt bleiben. Andernfalls kann eine Anwendung hängen bleiben. Dies dient jedoch nicht nur Sperren, sondern ist ebenso entscheidend für jede Datenbank mit einer Art Transaktionsisolierung, einschließlich MySQL mit InnoDB. Jede Verbindung, die sich noch in einer alten Transaktion befindet, gibt veraltete Daten zurück, wenn diese Daten auf dieser Verbindung innerhalb der Isolation bereits abgefragt wurden. Hintergrundinformationen, warum Sie veraltete Daten auch auf MySQL sehen könnten, finden Sie unter https://dev.mysql.com/doc/refman/5.1/en/innodb-transaction-model.html.
Ich verwende MyISAM – wie schalte ich es aus?¶
Das Verhalten der Verbindungswiederherstellung des Verbindungspools kann mit reset_on_return konfiguriert werden.
from sqlalchemy import create_engine
from sqlalchemy.pool import QueuePool
engine = create_engine(
"mysql+mysqldb://scott:tiger@localhost/myisam_database",
pool=QueuePool(reset_on_return=False),
)Ich verwende SQL Server – wie verwandle ich diese ROLLBACKs in COMMITs?¶
reset_on_return akzeptiert die Werte commit, rollback zusätzlich zu True, False und None. Das Setzen auf commit bewirkt einen COMMIT, wenn eine Verbindung zum Pool zurückgegeben wird.
engine = create_engine(
"mssql+pyodbc://scott:tiger@mydsn", pool=QueuePool(reset_on_return="commit")
)Ich verwende mehrere Verbindungen mit einer SQLite-Datenbank (typischerweise zum Testen von Transaktionsoperationen) und mein Testprogramm funktioniert nicht!¶
Wenn Sie eine SQLite :memory:-Datenbank verwenden, ist der Standard-Verbindungspool der SingletonThreadPool, der genau eine SQLite-Verbindung pro Thread aufrechterhält. Zwei Verbindungen, die im selben Thread verwendet werden, sind also tatsächlich dieselbe SQLite-Verbindung. Stellen Sie sicher, dass Sie keine :memory:-Datenbank verwenden, damit die Engine den QueuePool verwendet (Standard für Nicht-Memory-Datenbanken in aktuellen SQLAlchemy-Versionen).
Siehe auch
Threading/Pooling Verhalten – Informationen zum Verhalten von PySQLite.
Wie greife ich auf die rohe DBAPI-Verbindung zu, wenn ich eine Engine verwende?¶
Mit einer regulären SA-Engine-Level-Verbindung können Sie über das Attribut Connection.connection auf eine Pool-proxierte Version der DBAPI-Verbindung zugreifen. Für die wirkliche DBAPI-Verbindung können Sie das Attribut PoolProxiedConnection.dbapi_connection auf dieser aufrufen. Bei regulären Synchronisations-Treibern ist es normalerweise nicht notwendig, auf die nicht-Pool-proxierte DBAPI-Verbindung zuzugreifen, da alle Methoden über den Proxy aufgerufen werden.
engine = create_engine(...)
conn = engine.connect()
# pep-249 style PoolProxiedConnection (historically called a "connection fairy")
connection_fairy = conn.connection
# typically to run statements one would get a cursor() from this
# object
cursor_obj = connection_fairy.cursor()
# ... work with cursor_obj
# to bypass "connection_fairy", such as to set attributes on the
# unproxied pep-249 DBAPI connection, use .dbapi_connection
raw_dbapi_connection = connection_fairy.dbapi_connection
# the same thing is available as .driver_connection (more on this
# in the next section)
also_raw_dbapi_connection = connection_fairy.driver_connectionGeändert in Version 1.4.24: Hinzugefügt wurde das Attribut PoolProxiedConnection.dbapi_connection, das das vorherige Attribut PoolProxiedConnection.connection ersetzt, das weiterhin verfügbar ist; dieses Attribut stellt immer ein synchrones PEP 249-Verbindungsobjekt bereit. Das Attribut PoolProxiedConnection.driver_connection wird ebenfalls hinzugefügt, das immer auf die echte Treiber-Level-Verbindung verweist, unabhängig davon, welche API sie präsentiert.
Zugriff auf die zugrunde liegende Verbindung für einen asyncio-Treiber¶
Wenn ein asyncio-Treiber verwendet wird, gibt es zwei Änderungen am obigen Schema. Erstens, wenn eine AsyncConnection verwendet wird, muss die PoolProxiedConnection mit der awaitable-Methode AsyncConnection.get_raw_connection() abgerufen werden. Die zurückgegebene PoolProxiedConnection behält in diesem Fall ein synchrones PEP 249-Verwendungsmuster bei, und das Attribut PoolProxiedConnection.dbapi_connection verweist auf ein SQLAlchemy-adaptiertes Verbindungsobjekt, das die asyncio-Verbindung an eine synchrone PEP 249-API anpasst. Mit anderen Worten, es gibt **zwei** Proxy-Ebenen bei der Verwendung eines asyncio-Treibers. Die tatsächliche asyncio-Verbindung ist über das Attribut driver_connection verfügbar. Um das vorherige Beispiel auf asyncio anzuwenden, sieht es wie folgt aus:
async def main():
engine = create_async_engine(...)
conn = await engine.connect()
# pep-249 style ConnectionFairy connection pool proxy object
# presents a sync interface
connection_fairy = await conn.get_raw_connection()
# beneath that proxy is a second proxy which adapts the
# asyncio driver into a pep-249 connection object, accessible
# via .dbapi_connection as is the same with a sync API
sqla_sync_conn = connection_fairy.dbapi_connection
# the really-real innermost driver connection is available
# from the .driver_connection attribute
raw_asyncio_connection = connection_fairy.driver_connection
# work with raw asyncio connection
result = await raw_asyncio_connection.execute(...)Geändert in Version 1.4.24: Hinzugefügt wurden die Attribute PoolProxiedConnection.dbapi_connection und PoolProxiedConnection.driver_connection, um den Zugriff auf PEP 249-Verbindungen, PEP 249-Adaptionsschichten und zugrunde liegende Treiberverbindungen über eine konsistente Schnittstelle zu ermöglichen.
Bei der Verwendung von asyncio-Treibern ist die obige „DBAPI“-Verbindung tatsächlich eine SQLAlchemy-adaptierte Form der Verbindung, die eine synchrone PEP 249-API bereitstellt. Um auf die tatsächliche asyncio-Treiberverbindung zuzugreifen, die die ursprüngliche asyncio-API des verwendeten Treibers bereitstellt, kann über das Attribut PoolProxiedConnection.driver_connection von PoolProxiedConnection darauf zugegriffen werden. Für einen Standard-PEP 249-Treiber sind PoolProxiedConnection.dbapi_connection und PoolProxiedConnection.driver_connection synonym.
Sie müssen sicherstellen, dass Sie alle Isolationslevel-Einstellungen oder andere operationsspezifische Einstellungen für die Verbindung zurücksetzen, bevor Sie sie an den Pool zurückgeben.
Als Alternative zum Zurücksetzen von Einstellungen können Sie die Methode Connection.detach() entweder auf Connection oder auf der proxierten Verbindung aufrufen, wodurch die Verbindung vom Pool getrennt wird, sodass sie geschlossen und verworfen wird, wenn Connection.close() aufgerufen wird.
conn = engine.connect()
conn.detach() # detaches the DBAPI connection from the connection pool
conn.connection.<go nuts>
conn.close() # connection is closed for real, the pool replaces it with a new connectionWie verwende ich Engines / Verbindungen / Sitzungen mit Python-Multiprocessing oder os.fork()?¶
Dies wird im Abschnitt Verwendung von Verbindungspools mit Multiprocessing oder os.fork() behandelt.
Die Designs von flambé! dem Drachen und Der Alchemist wurden von Rotem Yaari erstellt und großzügig gespendet.
Erstellt mit Sphinx 7.2.6. Dokumentation zuletzt generiert: Di 11 Mär 2025 14:40:17 EDT