SQLAlchemy 2.0 Dokumentation
SQLAlchemy ORM
- ORM Schnellstart
- ORM Abgebildete Klassenkonfiguration
- Beziehungskonfiguration
- ORM Abfragehandbuch
- Verwendung der Sitzung
- Sitzungsgrundlagen¶
- Was macht die Sitzung?
- Grundlagen der Sitzungsverwendung
- Öffnen und Schließen einer Sitzung
- Einrichten eines begin / commit / rollback-Blocks
- Verwendung eines sessionmaker
- Abfragen
- Hinzufügen neuer oder bestehender Elemente
- Löschen
- Flushing
- Abrufen nach Primärschlüssel
- Ablaufen / Aktualisieren
- UPDATE und DELETE mit beliebiger WHERE-Klausel
- Automatisches Beginnen
- Commit
- Rollback
- Schließen
- Sitzungs-Häufig gestellte Fragen
- Wann erstelle ich einen
sessionmaker? - Wann konstruiere ich eine
Session, wann committe ich sie und wann schließe ich sie? - Ist die Sitzung ein Cache?
- Wie bekomme ich die
Sessionfür ein bestimmtes Objekt? - Ist die Sitzung Thread-sicher? Ist AsyncSession sicher, in gleichzeitigen Aufgaben geteilt zu werden?
- Wann erstelle ich einen
- Zustandsverwaltung
- Kaskaden
- Transaktionen und Verbindungsverwaltung
- Zusätzliche Persistenztechniken
- Kontextuelle/Thread-lokale Sessions
- Abfragen, Objekte und Session-Änderungen mit Events verfolgen
- Session API
- Sitzungsgrundlagen¶
- Ereignisse und Interna
- ORM Erweiterungen
- ORM Beispiele
Projektversionen
- Vorheriges: Verwendung der Sitzung
- Nächstes: Zustandsverwaltung
- Nach oben: Startseite
- Auf dieser Seite
- Grundlagen der Session
- Was macht die Sitzung?
- Grundlagen der Sitzungsverwendung
- Öffnen und Schließen einer Sitzung
- Einrichten eines begin / commit / rollback-Blocks
- Verwendung eines sessionmaker
- Abfragen
- Hinzufügen neuer oder bestehender Elemente
- Löschen
- Flushing
- Abrufen nach Primärschlüssel
- Ablaufen / Aktualisieren
- UPDATE und DELETE mit beliebiger WHERE-Klausel
- Automatisches Beginnen
- Commit
- Rollback
- Schließen
- Sitzungs-Häufig gestellte Fragen
- Wann erstelle ich einen
sessionmaker? - Wann konstruiere ich eine
Session, wann committe ich sie und wann schließe ich sie? - Ist die Sitzung ein Cache?
- Wie bekomme ich die
Sessionfür ein bestimmtes Objekt? - Ist die Sitzung Thread-sicher? Ist AsyncSession sicher, in gleichzeitigen Aufgaben geteilt zu werden?
- Wann erstelle ich einen
Sitzungsgrundlagen¶
Was macht die Sitzung?¶
Im allgemeinsten Sinne etabliert die Session alle Konversationen mit der Datenbank und stellt eine „Wartezone“ für alle Objekte dar, die während ihrer Lebensdauer geladen oder ihr zugeordnet wurden. Sie bietet die Schnittstelle, über die SELECT- und andere Abfragen gemacht werden, die ORM-gemappte Objekte zurückgeben und ändern. Die ORM-Objekte selbst werden innerhalb der Session in einer Struktur namens Identity Map verwaltet – eine Datenstruktur, die eindeutige Kopien jedes Objekts beibehält, wobei „eindeutig“ bedeutet „nur ein Objekt mit einem bestimmten Primärschlüssel“.
Die Session beginnt in ihrem gebräuchlichsten Anwendungsmuster in einem weitgehend zustandslosen Zustand. Sobald Abfragen ausgeführt oder andere Objekte mit ihr persistiert wurden, fordert sie eine Verbindung von einer Engine an, die mit der Session verknüpft ist, und etabliert dann eine Transaktion auf dieser Verbindung. Diese Transaktion bleibt bestehen, bis die Session angewiesen wird, die Transaktion zu committen oder rückgängig zu machen. Wenn die Transaktion endet, wird die Verbindung, die mit der Engine verbunden war, an den vom Engine verwalteten Verbindungspool zurückgegeben. Eine neue Transaktion beginnt dann mit dem Auschecken einer neuen Verbindung.
Die von einer Session verwalteten ORM-Objekte sind so instrumentiert, dass immer dann, wenn ein Attribut oder eine Sammlung im Python-Programm geändert wird, ein Änderungsereignis generiert wird, das von der Session aufgezeichnet wird. Immer wenn die Datenbank abgefragt werden soll oder wenn die Transaktion committet werden soll, **flusht** die Session zuerst alle ausstehenden, im Speicher gespeicherten Änderungen in die Datenbank. Dies ist als das Unit of Work-Muster bekannt.
Bei der Verwendung einer Session ist es nützlich, die von ihr verwalteten ORM-gemappten Objekte als **Proxy-Objekte** für Datenbankzeilen zu betrachten, die lokal für die von der Session gehaltene Transaktion sind. Um den Zustand der Objekte mit dem tatsächlichen Zustand in der Datenbank übereinstimmend zu halten, gibt es eine Vielzahl von Ereignissen, die dazu führen, dass Objekte die Datenbank erneut abfragen, um synchronisiert zu bleiben. Es ist möglich, Objekte von einer Session zu „trennen“ und sie weiterhin zu verwenden, obwohl diese Praxis ihre Vorbehalte hat. Es ist beabsichtigt, dass Sie getrennte Objekte normalerweise wieder mit einer anderen Session wieder verbinden, wenn Sie wieder mit ihnen arbeiten möchten, damit sie ihre normale Aufgabe der Darstellung des Datenbankzustands wieder aufnehmen können.
Grundlagen der Sitzungsverwendung¶
Die grundlegendsten Anwendungsmuster einer Session werden hier vorgestellt.
Öffnen und Schließen einer Sitzung¶
Die Session kann eigenständig oder mithilfe der Klasse sessionmaker konstruiert werden. Sie erhält normalerweise eine einzelne Engine als Quelle für die Konnektivität im Voraus. Eine typische Verwendung könnte so aussehen:
from sqlalchemy import create_engine
from sqlalchemy.orm import Session
# an Engine, which the Session will use for connection
# resources
engine = create_engine("postgresql+psycopg2://scott:tiger@localhost/")
# create session and add objects
with Session(engine) as session:
session.add(some_object)
session.add(some_other_object)
session.commit()Oben wird die Session mit einer Engine instanziiert, die mit einer bestimmten Datenbank-URL verknüpft ist. Sie wird dann in einem Python-Kontextmanager (d.h. einer with:-Anweisung) verwendet, damit sie am Ende des Blocks automatisch geschlossen wird; dies ist äquivalent zum Aufruf der Methode Session.close().
Der Aufruf von Session.commit() ist optional und nur dann erforderlich, wenn die mit der Session durchgeführten Arbeiten neue Daten enthalten, die in der Datenbank persistiert werden sollen. Wenn wir nur SELECT-Aufrufe getätigt hätten und keine Änderungen schreiben müssten, dann wäre der Aufruf von Session.commit() nicht notwendig.
Hinweis
Beachten Sie, dass nach dem Aufruf von Session.commit(), sei es explizit oder bei Verwendung eines Kontextmanagers, alle mit der Session verbundenen Objekte abgelaufen sind, d.h. ihr Inhalt wird gelöscht, um im nächsten Transaktionsblock neu geladen zu werden. Wenn diese Objekte stattdessen getrennt werden, sind sie nicht funktionsfähig, bis sie wieder mit einer neuen Session verbunden werden, es sei denn, der Parameter Session.expire_on_commit wird verwendet, um dieses Verhalten zu deaktivieren. Siehe den Abschnitt Committing für weitere Details.
Einrichten eines begin / commit / rollback-Blocks¶
Wir können den Aufruf von Session.commit() und die allgemeine „Rahmung“ der Transaktion in einem Kontextmanager für Fälle einschließen, in denen wir Daten in die Datenbank committen werden. Mit „Rahmung“ meinen wir, dass, wenn alle Operationen erfolgreich sind, die Methode Session.commit() aufgerufen wird, aber wenn Ausnahmen ausgelöst werden, wird die Methode Session.rollback() aufgerufen, sodass die Transaktion sofort rückgängig gemacht wird, bevor die Ausnahme nach außen weitergegeben wird. In Python wird dies am grundlegendsten mithilfe eines try: / except: / else:-Blocks ausgedrückt, wie zum Beispiel:
# verbose version of what a context manager will do
with Session(engine) as session:
session.begin()
try:
session.add(some_object)
session.add(some_other_object)
except:
session.rollback()
raise
else:
session.commit()Die oben gezeigte lange Abfolge von Operationen kann durch die Verwendung des Objekts SessionTransaction, das von der Methode Session.begin() zurückgegeben wird, die eine Kontextmanager-Schnittstelle für dieselbe Abfolge von Operationen bietet, prägnanter erreicht werden.
# create session and add objects
with Session(engine) as session:
with session.begin():
session.add(some_object)
session.add(some_other_object)
# inner context calls session.commit(), if there were no exceptions
# outer context calls session.close()Prägnanter können die beiden Kontexte kombiniert werden.
# create session and add objects
with Session(engine) as session, session.begin():
session.add(some_object)
session.add(some_other_object)
# inner context calls session.commit(), if there were no exceptions
# outer context calls session.close()Verwendung eines sessionmaker¶
Der Zweck von sessionmaker ist es, eine Fabrik für Session-Objekte mit einer festen Konfiguration bereitzustellen. Da es typisch ist, dass eine Anwendung eine Engine im Modul-Scope hat, kann sessionmaker eine Fabrik für Session-Objekte bereitstellen, die gegen diese Engine konstruiert werden.
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
# an Engine, which the Session will use for connection
# resources, typically in module scope
engine = create_engine("postgresql+psycopg2://scott:tiger@localhost/")
# a sessionmaker(), also in the same scope as the engine
Session = sessionmaker(engine)
# we can now construct a Session() without needing to pass the
# engine each time
with Session() as session:
session.add(some_object)
session.add(some_other_object)
session.commit()
# closes the sessionsessionmaker ist analog zur Engine als Modul-Ebene-Fabrik für Funktions-Ebene-Sitzungen/Verbindungen. Als solche hat sie auch ihre eigene Methode sessionmaker.begin(), analog zu Engine.begin(), die ein Session-Objekt zurückgibt und auch einen begin/commit/rollback-Block verwaltet.
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
# an Engine, which the Session will use for connection
# resources
engine = create_engine("postgresql+psycopg2://scott:tiger@localhost/")
# a sessionmaker(), also in the same scope as the engine
Session = sessionmaker(engine)
# we can now construct a Session() and include begin()/commit()/rollback()
# at once
with Session.begin() as session:
session.add(some_object)
session.add(some_other_object)
# commits the transaction, closes the sessionWo oben, wird die Session sowohl ihre Transaktion committen als auch die Session wird geschlossen, wenn der obige with:-Block endet.
Wenn Sie Ihre Anwendung schreiben, sollte die sessionmaker-Fabrik denselben Geltungsbereich haben wie das von create_engine() erstellte Engine-Objekt, was typischerweise im Modul- oder globalen Geltungsbereich liegt. Da diese Objekte beides Fabriken sind, können sie gleichzeitig von beliebig vielen Funktionen und Threads verwendet werden.
Abfragen¶
Das primäre Mittel zur Abfrage ist die Verwendung des Konstrukts select(), um ein Select-Objekt zu erstellen, das dann ausgeführt wird, um mithilfe von Methoden wie Session.execute() und Session.scalars() ein Ergebnis zurückzugeben. Ergebnisse werden dann in Form von Result-Objekten zurückgegeben, einschließlich Untervarianten wie ScalarResult.
Ein vollständiger Leitfaden zur SQLAlchemy ORM-Abfrage finden Sie im Leitfaden zur ORM-Abfrage. Einige kurze Beispiele folgen:
from sqlalchemy import select
from sqlalchemy.orm import Session
with Session(engine) as session:
# query for ``User`` objects
statement = select(User).filter_by(name="ed")
# list of ``User`` objects
user_obj = session.scalars(statement).all()
# query for individual columns
statement = select(User.name, User.fullname)
# list of Row objects
rows = session.execute(statement).all()Geändert in Version 2.0: Die Abfrage im „2.0“-Stil ist jetzt Standard. Weitere Migrationshinweise aus der 1.x-Reihe finden Sie unter 2.0 Migration - ORM-Verwendung.
Siehe auch
Hinzufügen neuer oder bestehender Elemente¶
Session.add() wird verwendet, um Instanzen in die Sitzung zu legen. Für transiente (d.h. brandneue) Instanzen hat dies zur Folge, dass bei der nächsten Überprüfung ein INSERT für diese Instanzen ausgeführt wird. Für Instanzen, die persistent sind (d.h. von dieser Sitzung geladen wurden), sind sie bereits vorhanden und müssen nicht hinzugefügt werden. Getrennte Instanzen (d.h. aus einer Sitzung entfernt) können mit dieser Methode wieder mit einer Sitzung verknüpft werden.
user1 = User(name="user1")
user2 = User(name="user2")
session.add(user1)
session.add(user2)
session.commit() # write changes to the databaseUm eine Liste von Elementen auf einmal zur Sitzung hinzuzufügen, verwenden Sie Session.add_all().
session.add_all([item1, item2, item3])Die Operation Session.add() **kaskadiert** entlang der save-update-Kaskade. Weitere Details finden Sie im Abschnitt Kaskaden.
Löschen¶
Die Methode Session.delete() platziert eine Instanz in der Liste der zu löschenden Objekte der Sitzung.
# mark two objects to be deleted
session.delete(obj1)
session.delete(obj2)
# commit (or flush)
session.commit()Session.delete() markiert ein Objekt zum Löschen, was zu einer DELETE-Anweisung für jeden betroffenen Primärschlüssel führt. Bevor die ausstehenden Löschungen durchgeführt werden, sind die mit „delete“ markierten Objekte in der Sammlung Session.deleted vorhanden. Nach dem DELETE werden sie aus der Session entfernt, was nach dem Committen der Transaktion dauerhaft wird.
Es gibt verschiedene wichtige Verhaltensweisen im Zusammenhang mit der Operation Session.delete(), insbesondere im Hinblick auf Beziehungen zu anderen Objekten und Sammlungen. Weitere Informationen dazu finden Sie im Abschnitt Kaskaden, aber im Allgemeinen gelten folgende Regeln:
Zeilen, die zu gemappten Objekten gehören, die über die Direktive
relationship()mit einem gelöschten Objekt in Beziehung stehen, werden **standardmäßig nicht gelöscht**. Wenn diese Objekte eine Fremdschlüsselbeschränkung zurück zu der gelöschten Zeile haben, werden diese Spalten auf NULL gesetzt. Dies führt zu einem Verstoß gegen die Beschränkung, wenn die Spalten nicht NULL sein dürfen.Um das „SET NULL“ in ein Löschen der Zeile eines verwandten Objekts zu ändern, verwenden Sie die **delete**-Kaskade auf der
relationship(). Siehe Kaskadenelement löschen.Zeilen in Tabellen, die als „Many-to-Many“-Tabellen über den Parameter
relationship.secondaryverknüpft sind, werden **in allen Fällen gelöscht**, wenn das Objekt, auf das sie verweisen, gelöscht wird.Wenn verwandte Objekte eine Fremdschlüsselbeschränkung zurück zu dem gelöschten Objekt enthalten und die verwandten Sammlungen, zu denen sie gehören, nicht gerade im Speicher geladen sind, gibt die Unit of Work ein SELECT aus, um alle verwandten Zeilen abzurufen, damit deren Primärschlüsselwerte verwendet werden können, um UPDATE- oder DELETE-Anweisungen für diese verwandten Zeilen auszugeben. Auf diese Weise erfüllt die ORM ohne weitere Anweisungen die Funktion von ON DELETE CASCADE, auch wenn dies auf Core
ForeignKeyConstraint-Objekten konfiguriert ist.Der Parameter
relationship.passive_deleteskann verwendet werden, um dieses Verhalten zu steuern und sich auf „ON DELETE CASCADE“ natürlicher zu verlassen; wenn er auf True gesetzt ist, findet diese SELECT-Operation nicht mehr statt, jedoch unterliegen lokal vorhandene Zeilen immer noch explizitem SET NULL oder DELETE. Das Setzen vonrelationship.passive_deletesauf den String"all"deaktiviert **alle** Updates/Deletes verwandter Objekte.Wenn das DELETE für ein zum Löschen markiertes Objekt erfolgt, wird das Objekt nicht automatisch aus Sammlungen oder Objektverweisen entfernt, die darauf verweisen. Wenn die
Sessionabgelaufen ist, können diese Sammlungen erneut geladen werden, sodass das Objekt nicht mehr vorhanden ist. Es ist jedoch vorzuziehen, dass das Objekt anstattSession.delete()für diese Objekte stattdessen aus seiner Sammlung entfernt und dann delete-orphan verwendet wird, sodass es als sekundäre Auswirkung dieser Sammlungentfernung gelöscht wird. Siehe den Abschnitt Hinweise zum Löschen – Objekte löschen, auf die aus Sammlungen und skalaren Beziehungen verwiesen wird für ein Beispiel.
Siehe auch
delete – beschreibt „delete cascade“, die verwandte Objekte zum Löschen markiert, wenn ein führendes Objekt gelöscht wird.
delete-orphan – beschreibt „delete orphan cascade“, die verwandte Objekte zum Löschen markiert, wenn sie von ihrem führenden Objekt getrennt werden.
Hinweise zum Löschen – Objekte löschen, auf die aus Sammlungen und skalaren Beziehungen verwiesen wird – wichtiger Hintergrund zu Session.delete() im Zusammenhang mit der Aktualisierung von Beziehungen im Speicher.
Flush¶
Wenn die Session mit ihrer Standardkonfiguration verwendet wird, wird der Flush-Schritt fast immer transparent durchgeführt. Insbesondere erfolgt der Flush vor jeder einzelnen SQL-Anweisung, die als Ergebnis einer Query oder eines 2.0-Stil Session.execute()-Aufrufs ausgegeben wird, sowie innerhalb des Aufrufs von Session.commit(), bevor die Transaktion committet wird. Er erfolgt auch vor der Ausgabe eines SAVEPOINT, wenn Session.begin_nested() verwendet wird.
Ein Session-Flush kann jederzeit durch Aufruf der Methode Session.flush() erzwungen werden.
session.flush()Der Flush, der automatisch im Geltungsbereich bestimmter Methoden erfolgt, wird als **autoflush** bezeichnet. Autoflush ist definiert als ein konfigurierbarer, automatischer Flush-Aufruf, der zu Beginn von Methoden erfolgt, einschließlich:
Session.execute()und anderen SQL-ausgebenden Methoden, wenn sie gegen ORM-fähige SQL-Konstrukte verwendet werden, wie z.B.select()-Objekte, die auf ORM-Entitäten und/oder ORM-gemappte Attribute verweisen.Wenn eine
Queryaufgerufen wird, um SQL an die Datenbank zu senden.Innerhalb der Methode
Session.merge()vor der Abfrage der Datenbank.Wenn Objekte aktualisiert werden.
Wenn ORM Lazy Load-Operationen gegen nicht geladene Objektattribute erfolgen.
Es gibt auch Zeitpunkte, zu denen Flushes **bedingungslos** erfolgen; diese Zeitpunkte liegen innerhalb wichtiger transaktionaler Grenzen, darunter:
Im Prozess der Methode
Session.commit().Wenn
Session.begin_nested()aufgerufen wird.Wenn die 2PC-Methode
Session.prepare()verwendet wird.
Das **autoflush**-Verhalten, wie es auf die vorherige Liste von Elementen angewendet wird, kann deaktiviert werden, indem eine Session oder ein sessionmaker mit dem Parameter Session.autoflush auf False konstruiert wird.
Session = sessionmaker(autoflush=False)Zusätzlich kann autoflush vorübergehend innerhalb des Ablaufs der Verwendung einer Session mithilfe des Kontextmanagers Session.no_autoflush deaktiviert werden.
with mysession.no_autoflush:
mysession.add(some_object)
mysession.flush()Zur Wiederholung: Der Flush-Prozess **erfolgt immer**, wenn transaktionale Methoden wie Session.commit() und Session.begin_nested() aufgerufen werden, unabhängig von „autoflush“-Einstellungen, wenn die Session noch ausstehende Änderungen zu verarbeiten hat.
Da die Session SQL nur im Kontext einer DBAPI-Transaktion zur Datenbank ausgibt, erfolgen alle „Flush“-Operationen selbst nur innerhalb einer Datenbanktransaktion (abhängig vom Isolationslevel der Datenbanktransaktion), vorausgesetzt, die DBAPI befindet sich nicht im Modus Treiber-Autocommit. Das bedeutet, dass unter der Annahme, dass die Datenbankverbindung für Atomarität innerhalb ihrer Transaktionseinstellungen sorgt, bei einem Fehler einer einzelnen DML-Anweisung innerhalb des Flushes die gesamte Operation rückgängig gemacht wird.
Wenn ein Fehler während eines Flushes auftritt, ist ein expliziter Aufruf von Session.rollback() erforderlich, um diese gleiche Session weiterhin verwenden zu können, auch wenn die zugrunde liegende Transaktion bereits rückgängig gemacht wurde (selbst wenn der Datenbanktreiber technisch gesehen im Treiber-Autocommit-Modus ist). Dies geschieht, um das allgemeine Verschachtelungsmuster sogenannter „Subtransaktionen“ konsistent aufrechtzuerhalten. Der FAQ-Abschnitt „Diese Transaktion der Sitzung wurde aufgrund einer vorherigen Ausnahme während des Flushs zurückgesetzt.“ (oder ähnlich) enthält eine detailliertere Beschreibung dieses Verhaltens.
Siehe auch
„Diese Transaktion der Sitzung wurde aufgrund einer vorherigen Ausnahme während des Flushs zurückgesetzt.“ (oder ähnlich) – weiterer Hintergrund dazu, warum Session.rollback() aufgerufen werden muss, wenn ein Flush fehlschlägt.
Abrufen nach Primärschlüssel¶
Da die Session eine Identity Map verwendet, die aktuelle In-Memory-Objekte nach Primärschlüssel referenziert, wird die Methode Session.get() als Mittel zur Lokalisierung von Objekten nach Primärschlüssel bereitgestellt. Sie sucht zuerst in der aktuellen Identity Map und fragt dann die Datenbank nach nicht vorhandenen Werten ab. Zum Beispiel, um eine User-Entität mit der Primärschlüsselidentität (5, ) zu lokalisieren.
my_user = session.get(User, 5)Das Session.get() enthält auch Aufruf-Formen für zusammengesetzte Primärschlüsselwerte, die als Tupel oder Dictionaries übergeben werden können, sowie zusätzliche Parameter, die spezifische Lade- und Ausführungsoptionen ermöglichen. Siehe Session.get() für die vollständige Parameterliste.
Siehe auch
Ablaufen / Aktualisieren¶
Eine wichtige Überlegung, die bei der Verwendung der Session häufig auftritt, ist der Umgang mit dem Zustand von Objekten, die aus der Datenbank geladen wurden, insbesondere im Hinblick auf deren Synchronisierung mit dem aktuellen Zustand der Transaktion. Die SQLAlchemy ORM basiert auf dem Konzept einer Identitätszuordnung, sodass beim Laden eines Objekts aus einer SQL-Abfrage eine eindeutige Python-Objektinstanz, die einer bestimmten Datenbankidentität entspricht, beibehalten wird. Das bedeutet, wenn wir zwei separate Abfragen für dieselbe Zeile ausgeben und ein zugeordnetes Objekt zurückerhalten, geben die beiden Abfragen dasselbe Python-Objekt zurück.
>>> u1 = session.scalars(select(User).where(User.id == 5)).one()
>>> u2 = session.scalars(select(User).where(User.id == 5)).one()
>>> u1 is u2
TrueDaraus ergibt sich, dass die ORM beim Zurückgeben von Zeilen aus einer Abfrage die **Befüllung von Attributen überspringt** für ein Objekt, das bereits geladen ist. Die Designannahme hierbei ist, von einer perfekt isolierten Transaktion auszugehen, und in dem Maße, in dem die Transaktion nicht isoliert ist, kann die Anwendung nach Bedarf Schritte unternehmen, um Objekte aus der Datenbanktransaktion zu aktualisieren. Der FAQ-Eintrag unter Ich lade Daten mit meiner Session neu, aber sie sieht keine Änderungen, die ich woanders committet habe behandelt dieses Konzept detaillierter.
Wenn ein ORM-zugeordnetes Objekt in den Speicher geladen wird, gibt es drei allgemeine Möglichkeiten, dessen Inhalt mit neuen Daten aus der aktuellen Transaktion zu aktualisieren:
die expire()-Methode - die Methode
Session.expire()löscht den Inhalt ausgewählter oder aller Attribute eines Objekts, sodass diese beim nächsten Zugriff aus der Datenbank geladen werden, z. B. mithilfe eines verzögerten Ladens.session.expire(u1) u1.some_attribute # <-- lazy loads from the transaction
die refresh()-Methode - eng damit verbunden ist die Methode
Session.refresh(), die alles tut, was die MethodeSession.expire()tut, aber auch sofort eine oder mehrere SQL-Abfragen ausgibt, um den Inhalt des Objekts tatsächlich zu aktualisieren.session.refresh(u1) # <-- emits a SQL query u1.some_attribute # <-- is refreshed from the transaction
die populate_existing()-Methode oder Ausführungsoption - Dies ist nun eine Ausführungsoption, die unter Vorhandene befüllen dokumentiert ist; in älterer Form ist sie im
Query-Objekt als MethodeQuery.populate_existing()zu finden. Diese Operation in jeder Form gibt an, dass von einer Abfrage zurückgegebene Objekte bedingungslos aus ihrem Inhalt in der Datenbank neu befüllt werden sollen.u2 = session.scalars( select(User).where(User.id == 5).execution_options(populate_existing=True) ).one()
Weitere Diskussionen zum Refresh/Expire-Konzept finden Sie unter Aktualisieren / Verfallenlassen.
UPDATE und DELETE mit beliebiger WHERE-Klausel¶
SQLAlchemy 2.0 beinhaltet erweiterte Funktionen zum Ausgeben verschiedener Arten von ORM-aktivierten INSERT-, UPDATE- und DELETE-Anweisungen. Dokumentation finden Sie im Dokument ORM-aktivierte INSERT-, UPDATE- und DELETE-Anweisungen.
Automatisches Beginnen¶
Das Session-Objekt verfügt über ein Verhalten namens **autobegin**. Dies bedeutet, dass die Session sich intern in einem „transaktionalen“ Zustand befindet, sobald eine Aktion mit der Session durchgeführt wird, sei es durch Änderungen am internen Zustand der Session bezüglich Objektzustandsänderungen oder durch Operationen, die eine Datenbankverbindung erfordern.
Wenn die Session zum ersten Mal konstruiert wird, ist kein transaktionaler Zustand vorhanden. Der transaktionale Zustand wird automatisch begonnen, wenn eine Methode wie Session.add() oder Session.execute() aufgerufen wird, oder ähnlich, wenn eine Query ausgeführt wird, um Ergebnisse zurückzugeben (was letztendlich Session.execute() verwendet), oder wenn ein Attribut eines persistenten Objekts geändert wird.
Der transaktionale Zustand kann durch Aufruf der Methode Session.in_transaction() überprüft werden, die True oder False zurückgibt, je nachdem, ob der „autobegin“-Schritt fortgeschritten ist. Obwohl normalerweise nicht benötigt, gibt die Methode Session.get_transaction() das tatsächliche SessionTransaction-Objekt zurück, das diesen transaktionalen Zustand darstellt.
Der transaktionale Zustand der Session kann auch explizit gestartet werden, indem die Methode Session.begin() aufgerufen wird. Wenn diese Methode aufgerufen wird, wird die Session bedingungslos in den „transaktionalen“ Zustand versetzt. Session.begin() kann als Kontextmanager verwendet werden, wie unter Einen Block für begin / commit / rollback gestalten beschrieben.
Deaktivieren von Autobegin zur Verhinderung impliziter Transaktionen¶
Das „autobegin“-Verhalten kann durch Setzen des Parameters Session.autobegin auf False deaktiviert werden. Durch die Verwendung dieses Parameters erfordert eine Session, dass die Methode Session.begin() explizit aufgerufen wird. Nach der Konstruktion sowie nach jedem Aufruf der Methoden Session.rollback(), Session.commit() oder Session.close() beginnt die Session nicht implizit neue Transaktionen und löst einen Fehler aus, wenn ein Versuch unternommen wird, die Session zu verwenden, ohne vorher Session.begin() aufzurufen.
with Session(engine, autobegin=False) as session:
session.begin() # <-- required, else InvalidRequestError raised on next call
session.add(User(name="u1"))
session.commit()
session.begin() # <-- required, else InvalidRequestError raised on next call
u1 = session.scalar(select(User).filter_by(name="u1"))Neu in Version 2.0: Hinzugefügt Session.autobegin, was die Deaktivierung des „autobegin“-Verhaltens ermöglicht.
Commit¶
Session.commit() wird verwendet, um die aktuelle Transaktion zu committen. Im Kern bedeutet dies, dass es COMMIT an alle aktuellen Datenbankverbindungen sendet, die eine laufende Transaktion haben; aus Sicht von DBAPI wird die connection.commit() DBAPI-Methode für jede DBAPI-Verbindung aufgerufen.
Wenn für die Session keine Transaktion aktiv ist, was bedeutet, dass seit dem letzten Aufruf von Session.commit() keine Operationen auf dieser Session durchgeführt wurden, beginnt die Methode eine interne „logische“ Transaktion und committet sie. Diese beeinflusst normalerweise die Datenbank nicht, es sei denn, es wurden ausstehende Flush-Änderungen erkannt, ruft aber dennoch Ereignishandler und Objekt-Verfallregeln auf.
Die Operation Session.commit() führt bedingungslos einen Session.flush() aus, bevor sie COMMIT an die relevanten Datenbankverbindungen sendet. Wenn keine ausstehenden Änderungen erkannt werden, wird keine SQL an die Datenbank gesendet. Dieses Verhalten ist nicht konfigurierbar und wird nicht vom Parameter Session.autoflush beeinflusst.
Anschließend, unter der Annahme, dass die Session an eine Engine gebunden ist, committet Session.commit() dann die tatsächliche Datenbanktransaktion, falls eine gestartet wurde. Nach dem Commit wird das Connection-Objekt, das mit dieser Transaktion verbunden ist, geschlossen, wodurch die zugrunde liegende DBAPI-Verbindung an den Connection Pool der Engine zurückgegeben wird, an die die Session gebunden ist.
Für eine Session, die an mehrere Engines gebunden ist (z. B. wie unter Partitionierungsstrategien beschrieben), werden dieselben COMMIT-Schritte für jede Engine / Connection durchgeführt, die innerhalb der zu committenden „logischen“ Transaktion aktiv sind. Diese Datenbanktransaktionen sind untereinander unkoordiniert, es sei denn, die Zwei-Phasen-Funktionen sind aktiviert.
Andere Verbindungsmuster sind ebenfalls verfügbar, indem die Session direkt an eine Connection gebunden wird; in diesem Fall wird davon ausgegangen, dass eine extern verwaltete Transaktion vorhanden ist, und ein echtes COMMIT wird in diesem Fall nicht automatisch gesendet; siehe den Abschnitt Verbinden einer Session mit einer externen Transaktion (z. B. für Testsuiten) für Hintergrundinformationen zu diesem Muster.
Schließlich werden alle Objekte innerhalb der Session als verfallen markiert, wenn die Transaktion abgeschlossen ist. Dies geschieht, damit beim nächsten Zugriff auf die Instanzen, sei es durch Attributzugriff oder durch deren Anwesenheit im Ergebnis einer SELECT-Abfrage, der aktuellste Zustand abgerufen wird. Dieses Verhalten kann durch das Flag Session.expire_on_commit gesteuert werden, das auf False gesetzt werden kann, wenn dieses Verhalten unerwünscht ist.
Siehe auch
Rückgängig machen¶
Session.rollback() macht die aktuelle Transaktion, falls vorhanden, rückgängig. Wenn keine Transaktion aktiv ist, verläuft die Methode stillschweigend.
Mit einer standardmäßig konfigurierten Session ist der Zustand der Session nach dem Rückgängigmachen, nachdem eine Transaktion entweder über autobegin begonnen oder die Methode Session.begin() explizit aufgerufen wurde, wie folgt:
Datenbanktransaktionen werden rückgängig gemacht. Für eine
Session, die an eine einzelneEnginegebunden ist, bedeutet dies, dass für höchstens eine aktuell verwendeteConnectionROLLBACK ausgegeben wird. FürSession-Objekte, die an mehrereEngine-Objekte gebunden sind, wird ROLLBACK für alle ausgeliehenenConnection-Objekte ausgegeben.Datenbankverbindungen werden freigegeben. Dies folgt demselben verbindungbezogenen Verhalten, das unter Commit erwähnt wurde, wobei von
Engine-Objekten erhalteneConnection-Objekte geschlossen werden, was dazu führt, dass die DBAPI-Verbindungen im Connection Pool derEnginefreigegeben werden. Neue Verbindungen werden bei Bedarf von derEngineausgeliehen, wenn eine neue Transaktion beginnt.Für eine
Session, die direkt an eineConnectiongebunden ist, wie unter Verbinden einer Session mit einer externen Transaktion (z. B. für Testsuiten) beschrieben, folgt das Rollback-Verhalten auf dieserConnectiondem Verhalten, das durch den ParameterSession.join_transaction_modefestgelegt ist, was das Rückgängigmachen von Savepoints oder das Senden eines echten ROLLBACK beinhalten kann.Objekte, die sich zu Beginn der Transaktion im pending-Zustand befanden, als sie zur
Sessionhinzugefügt wurden, werden entfernt, was ihrem rückgängig gemachten INSERT-Statement entspricht. Der Zustand ihrer Attribute bleibt unverändert.Objekte, die innerhalb der Transaktion als deleted markiert waren, werden in den persistenten Zustand zurückversetzt, was ihrem rückgängig gemachten DELETE-Statement entspricht. Beachten Sie, dass, wenn diese Objekte zuerst pending innerhalb der Transaktion waren, diese Operation stattdessen Vorrang hat.
Alle Objekte, die nicht entfernt wurden, sind vollständig abgelaufen – dies ist unabhängig von der Einstellung
Session.expire_on_commit.
Mit diesem verstandenen Zustand kann die Session nach einem Rollback sicher weiterverwendet werden.
Geändert in Version 1.4: Das Session-Objekt verfügt nun über ein verzögertes „begin“-Verhalten, wie unter autobegin beschrieben. Wenn keine Transaktion begonnen wird, haben Methoden wie Session.commit() und Session.rollback() keine Auswirkung. Dieses Verhalten wurde vor 1.4 nicht beobachtet, da im Nicht-Autocommit-Modus immer implizit eine Transaktion vorhanden war.
Wenn ein Session.flush() fehlschlägt, typischerweise aus Gründen wie Primärschlüssel-, Fremdschlüssel- oder „nicht-null“-Constraint-Verletzungen, wird automatisch ein ROLLBACK ausgegeben (ein Flush kann derzeit nach einem Teilfehler nicht fortgesetzt werden). Die Session geht jedoch zu diesem Zeitpunkt in einen Zustand über, der als „inaktiv“ bekannt ist, und die aufrufende Anwendung muss immer explizit die Methode Session.rollback() aufrufen, damit die Session wieder in einen nutzbaren Zustand gelangen kann (sie kann auch einfach geschlossen und verworfen werden). Siehe den FAQ-Eintrag unter „Die Transaktion dieser Session wurde aufgrund einer früheren Ausnahme während des Flushes zurückgerollt.“ (oder ähnlich) für weitere Diskussionen.
Siehe auch
Schließen¶
Die Methode Session.close() gibt einen Session.expunge_all() aus, der alle ORM-zugeordneten Objekte aus der Session entfernt, und gibt alle transaktionalen/verbindungsbezogenen Ressourcen von den Engine-Objekten, an die sie gebunden ist, frei. Wenn Verbindungen an den Connection Pool zurückgegeben werden, wird auch der transaktionale Zustand rückgängig gemacht.
Standardmäßig ist die Session nach dem Schließen im Grunde im ursprünglichen Zustand wie beim ersten Konstruieren und **kann wieder verwendet werden**. In diesem Sinne ist die Methode Session.close() eher wie ein „Zurücksetzen“ in den sauberen Zustand und weniger wie eine Methode zum „Datenbank schließen“. In diesem Betriebsmodus ist die Methode Session.reset() ein Alias für Session.close() und verhält sich gleich.
Das Standardverhalten von Session.close() kann geändert werden, indem der Parameter Session.close_resets_only auf False gesetzt wird, was bedeutet, dass die Session nach dem Aufruf der Methode Session.close() nicht wiederverwendet werden kann. In diesem Betriebsmodus erlaubt die Methode Session.reset() mehrere „Reset“-Vorgänge der Session, wobei sie sich wie Session.close() verhält, wenn Session.close_resets_only auf True gesetzt ist.
Neu in Version 2.0.22.
Es wird empfohlen, den Geltungsbereich einer Session durch einen Aufruf von Session.close() am Ende zu begrenzen, insbesondere wenn die Methoden Session.commit() oder Session.rollback() nicht verwendet werden. Die Session kann als Kontextmanager verwendet werden, um sicherzustellen, dass Session.close() aufgerufen wird.
with Session(engine) as session:
result = session.execute(select(User))
# closes session automaticallyGeändert in Version 1.4: Das Session-Objekt verfügt über ein verzögertes „begin“-Verhalten, wie unter autobegin beschrieben. Nach dem Aufruf der Methode Session.close() wird nicht sofort eine neue Transaktion begonnen.
Häufig gestellte Fragen zu Sessions¶
An dieser Stelle haben viele Benutzer bereits Fragen zu Sessions. Dieser Abschnitt präsentiert eine Mini-FAQ (beachten Sie, dass wir auch eine echte FAQ haben) zu den grundlegendsten Problemen, mit denen man bei der Verwendung einer Session konfrontiert wird.
Wann erstelle ich einen sessionmaker?¶
Nur einmal, irgendwo im globalen Geltungsbereich Ihrer Anwendung. Er sollte als Teil Ihrer Anwendungskonfiguration betrachtet werden. Wenn Ihre Anwendung drei .py-Dateien in einem Paket hat, könnten Sie zum Beispiel die sessionmaker-Zeile in Ihre __init__.py-Datei einfügen; von da an sagen Ihre anderen Module „from mypackage import Session“. Auf diese Weise verwenden alle anderen einfach Session(), und die Konfiguration dieser Session wird von diesem zentralen Punkt aus gesteuert.
Wenn Ihre Anwendung startet, Importe durchführt, aber nicht weiß, mit welcher Datenbank sie sich verbinden wird, können Sie die Session auf „Klassen“-Ebene mit der Engine binden, indem Sie später sessionmaker.configure() verwenden.
In den Beispielen in diesem Abschnitt zeigen wir häufig, wie die sessionmaker direkt über der Zeile erstellt wird, in der wir tatsächlich die Session aufrufen. Aber das ist nur zum Beispiel! In Wirklichkeit wäre die sessionmaker irgendwo auf Modulebene angesiedelt. Die Aufrufe zur Instanziierung von Session würden dann an dem Punkt der Anwendung platziert, an dem Datenbankgespräche beginnen.
Wann konstruiere ich eine Session, wann committe ich sie und wann schließe ich sie?¶
Eine Session wird typischerweise zu Beginn einer logischen Operation konstruiert, bei der potenziell auf die Datenbank zugegriffen wird.
Die Session beginnt eine Datenbanktransaktion, sobald sie mit der Kommunikation beginnt, wenn sie zur Kommunikation mit der Datenbank verwendet wird. Diese Transaktion bleibt aktiv, bis die Session zurückgerollt, committet oder geschlossen wird. Die Session beginnt eine neue Transaktion, wenn sie nach dem Ende der vorherigen Transaktion erneut verwendet wird; daraus folgt, dass die Session über viele Transaktionen hinweg eine Lebensdauer haben kann, wenn auch nur eine zur Zeit. Wir bezeichnen diese beiden Konzepte als Transaktionsumfang und Sitzungsumfang.
Es ist normalerweise nicht sehr schwer, die besten Punkte zu bestimmen, an denen der Umfang einer Session begonnen und beendet werden soll, obwohl die große Vielfalt möglicher Anwendungsarchitekturen herausfordernde Situationen mit sich bringen kann.
Einige Beispielszenarien sind:
Webanwendungen. In diesem Fall ist es am besten, die SQLAlchemy-Integrationen zu nutzen, die vom verwendeten Web-Framework bereitgestellt werden. Andernfalls besteht das grundlegende Muster darin, am Anfang einer Webanfrage eine
Sessionzu erstellen, die MethodeSession.commit()am Ende von Webanfragen aufzurufen, die POST, PUT oder DELETE durchführen, und dann die Sitzung am Ende der Webanfrage zu schließen. Es ist auch normalerweise eine gute Idee,Session.expire_on_commitauf False zu setzen, damit nachfolgende Zugriffe auf Objekte, die von einerSessioninnerhalb der View-Schicht stammen, keine neuen SQL-Abfragen auslösen müssen, um die Objekte zu aktualisieren, wenn die Transaktion bereits committet wurde.Ein Hintergrund-Daemon, der Kindprozesse erzeugt, würde eine
Sessionerstellen, die für jeden Kindprozess lokal ist, mit dieserSessionwährend der Lebensdauer des „Jobs“ arbeiten, den der Fork bearbeitet, und sie dann abbauen, wenn der Job abgeschlossen ist.Für ein Kommandozeilen-Skript würde die Anwendung eine einzige, globale
Sessionerstellen, die beim Beginn der Arbeit des Programms eingerichtet wird, und sie kurz vor Abschluss der Aufgabe des Programms committen.Für eine GUI-gesteuerte Anwendung kann der Umfang der
Sessionam besten innerhalb des Umfangs eines benutzergenerierten Ereignisses liegen, wie z. B. einem Tastendruck. Oder der Umfang kann einer expliziten Benutzerinteraktion entsprechen, wie z. B. wenn der Benutzer eine Reihe von Datensätzen „öffnet“ und sie dann „speichert“.
Als allgemeine Regel sollte die Anwendung den Lebenszyklus der Sitzung extern zu Funktionen verwalten, die sich mit spezifischen Daten befassen. Dies ist eine grundlegende Trennung der Zuständigkeiten, die datenspezifische Operationen agnostisch gegenüber dem Kontext hält, in dem sie auf diese Daten zugreifen und diese manipulieren.
Z.B. nicht so machen
### this is the **wrong way to do it** ###
class ThingOne:
def go(self):
session = Session()
try:
session.execute(update(FooBar).values(x=5))
session.commit()
except:
session.rollback()
raise
class ThingTwo:
def go(self):
session = Session()
try:
session.execute(update(Widget).values(q=18))
session.commit()
except:
session.rollback()
raise
def run_my_program():
ThingOne().go()
ThingTwo().go()Halten Sie den Lebenszyklus der Sitzung (und normalerweise der Transaktion) getrennt und extern. Das folgende Beispiel zeigt, wie dies aussehen könnte, und nutzt zusätzlich einen Python-Kontextmanager (d. h. das Schlüsselwort with:), um den Umfang der Session und ihre Transaktion automatisch zu verwalten.
### this is a **better** (but not the only) way to do it ###
class ThingOne:
def go(self, session):
session.execute(update(FooBar).values(x=5))
class ThingTwo:
def go(self, session):
session.execute(update(Widget).values(q=18))
def run_my_program():
with Session() as session:
with session.begin():
ThingOne().go(session)
ThingTwo().go(session)Geändert in Version 1.4: Die Session kann als Kontextmanager verwendet werden, ohne externe Hilfsfunktionen zu nutzen.
Ist die Sitzung ein Cache?¶
Ja...nein. Sie wird etwas als Cache verwendet, da sie das Identity-Map-Muster implementiert und Objekte unter ihrem Primärschlüssel speichert. Sie macht jedoch keinerlei Abfrage-Caching. Das bedeutet, wenn Sie session.scalars(select(Foo).filter_by(name='bar')) sagen, auch wenn Foo(name='bar') direkt dort im Identity-Map vorhanden ist, hat die Sitzung davon keine Ahnung. Sie muss SQL an die Datenbank senden, die Zeilen zurückerhalten und dann, wenn sie den Primärschlüssel in der Zeile sieht, *dann* kann sie im lokalen Identity-Map nachsehen und feststellen, dass das Objekt bereits vorhanden ist. Nur wenn Sie query.get({some primary key}) sagen, muss die Session keine Abfrage senden.
Zusätzlich speichert die Sitzung standardmäßig Instanzen von Objekten mit schwachen Referenzen. Dies vereitelt auch den Zweck, die Sitzung als Cache zu verwenden.
Die Session ist nicht als globales Objekt konzipiert, das von jedem als „Registry“ von Objekten konsultiert wird. Das ist eher die Aufgabe eines Second-Level-Caches. SQLAlchemy bietet ein Muster zur Implementierung von Second-Level-Caching unter Verwendung von dogpile.cache über das Beispiel Dogpile Caching.
Wie bekomme ich die Session für ein bestimmtes Objekt?¶
Verwenden Sie die Klassenmethode Session.object_session(), die für Session verfügbar ist.
session = Session.object_session(someobject)Das neuere Runtime Inspection API-System kann ebenfalls verwendet werden.
from sqlalchemy import inspect
session = inspect(someobject).sessionIst die Sitzung threadsicher? Ist AsyncSession sicher für die gemeinsame Nutzung in konkurrierenden Tasks?¶
Die Session ist ein veränderbares, zustandsbehaftetes Objekt, das eine einzelne Datenbanktransaktion repräsentiert. Eine Instanz von Session kann daher nicht ohne sorgfältige Synchronisierung zwischen konkurrierenden Threads oder asyncio-Tasks geteilt werden. Die Session ist für die Verwendung in einer nicht-konkurrierenden Weise gedacht, d. h. eine bestimmte Instanz von Session sollte nur in einem Thread oder Task gleichzeitig verwendet werden.
Bei der Verwendung des AsyncSession-Objekts aus SQLAlchemy's asyncio-Erweiterung ist dieses Objekt nur ein dünner Proxy über einer Session, und dieselben Regeln gelten; es ist ein nicht synchronisiertes, veränderbares, zustandsbehaftetes Objekt, daher ist es nicht sicher, eine einzelne Instanz von AsyncSession gleichzeitig in mehreren asyncio-Tasks zu verwenden.
Eine Instanz von Session oder AsyncSession repräsentiert eine einzelne logische Datenbanktransaktion und bezieht sich zu einem bestimmten Zeitpunkt nur auf eine einzige Connection für eine bestimmte Engine oder AsyncEngine, an die das Objekt gebunden ist (beachten Sie, dass diese Objekte beide so konzipiert sind, dass sie gleichzeitig an mehrere Engines gebunden werden können, in diesem Fall wird jedoch immer noch nur eine Verbindung pro Engine im Geltungsbereich einer Transaktion aktiv sein).
Eine Datenbankverbindung innerhalb einer Transaktion ist ebenfalls ein zustandsbehaftetes Objekt, das für die nicht-konkurrierende, sequentielle Verarbeitung bestimmt ist. Befehle werden sequenziell an die Verbindung ausgegeben, die vom Datenbanksystem genau in der Reihenfolge verarbeitet werden, in der sie gesendet wurden. Während die Session Befehle über diese Verbindung ausgibt und Ergebnisse empfängt, durchläuft die Session selbst interne Zustandsänderungen, die mit dem Zustand der Befehle und der auf dieser Verbindung vorhandenen Daten übereinstimmen; Zustände, die beinhalten, ob eine Transaktion begonnen, committet oder zurückgerollt wurde, welche SAVEPOINTs, falls vorhanden, aktiv sind, sowie feinkörnige Synchronisation des Zustands einzelner Datenbankzeilen mit lokalen ORM-geführten Objekten.
Beim Entwerfen von Datenbankanwendungen für Nebenläufigkeit ist das geeignete Modell, dass jeder nebenläufige Task / Thread mit seiner eigenen Datenbanktransaktion arbeitet. Aus diesem Grund ist bei der Diskussion des Themas Datenbanknebenläufigkeit die Standardterminologie mehrere, nebenläufige Transaktionen. Innerhalb traditioneller RDMS gibt es kein Äquivalent für eine einzelne Datenbanktransaktion, die mehrere Befehle gleichzeitig empfängt und verarbeitet.
Das Nebenläufigkeitsmodell für SQLAlchemy's Session und AsyncSession ist daher Session pro Thread, AsyncSession pro Task. Eine Anwendung, die mehrere Threads oder mehrere Tasks in asyncio verwendet, z. B. bei der Verwendung einer API wie asyncio.gather(), sollte sicherstellen, dass jeder Thread seine eigene Session hat, jeder asyncio-Task seine eigene AsyncSession hat.
Der beste Weg, diese Verwendung sicherzustellen, ist die Verwendung des Standard-Kontextmanager-Musters lokal innerhalb der obersten Python-Funktion, die sich innerhalb des Threads oder Tasks befindet. Dies stellt sicher, dass die Lebensdauer der Session oder AsyncSession innerhalb eines lokalen Umfangs aufrechterhalten wird.
Für Anwendungen, die von einer „globalen“ Session profitieren, bei der es keine Option ist, das Session-Objekt an spezifische Funktionen und Methoden zu übergeben, die es benötigen, kann der scoped_session-Ansatz eine „Thread-lokale“ Session bereitstellen; siehe Abschnitt Kontextuelle/Thread-lokale Sitzungen für Hintergrundinformationen. Innerhalb des asyncio-Kontexts ist das Objekt async_scoped_session das asyncio-Analogon für scoped_session, erfordert jedoch eine komplexere Konfiguration, da eine benutzerdefinierte „Kontext“-Funktion benötigt wird.
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