Ein Sitzungsobjekt ist im Grunde eine laufende Transaktion von Änderungen an einer Datenbank (Aktualisieren, Einfügen, Löschen). Diese Vorgänge werden erst in der Datenbank gespeichert, wenn sie festgeschrieben wurden (wenn Ihr Programm während der Sitzungstransaktion aus irgendeinem Grund abgebrochen wird, gehen alle nicht festgeschriebenen Änderungen in der Datenbank verloren).
Das Sitzungsobjekt registriert Transaktionsoperationen bei session.add()
, kommuniziert sie jedoch noch nicht an die Datenbank, bis sie session.flush()
aufgerufen wird.
session.flush()
kommuniziert eine Reihe von Operationen an die Datenbank (Einfügen, Aktualisieren, Löschen). Die Datenbank verwaltet sie als ausstehende Vorgänge in einer Transaktion. Die Änderungen werden nicht dauerhaft auf der Festplatte gespeichert oder sind für andere Transaktionen sichtbar, bis die Datenbank ein COMMIT für die aktuelle Transaktion erhält (was auch der session.commit()
Fall ist).
session.commit()
Übernimmt diese Änderungen in die Datenbank.
flush()
wird immer als Teil eines Aufrufs von commit()
( 1 ) aufgerufen .
Wenn Sie ein Sitzungsobjekt zum Abfragen der Datenbank verwenden, gibt die Abfrage Ergebnisse sowohl aus der Datenbank als auch aus den gelöschten Teilen der darin nicht festgeschriebenen Transaktion zurück. Standardmäßig widerspricht Session autoflush
ihren Vorgängen, dies kann jedoch deaktiviert werden.
Hoffentlich wird dieses Beispiel dies klarer machen:
#---
s = Session()
s.add(Foo('A')) # The Foo('A') object has been added to the session.
# It has not been committed to the database yet,
# but is returned as part of a query.
print 1, s.query(Foo).all()
s.commit()
#---
s2 = Session()
s2.autoflush = False
s2.add(Foo('B'))
print 2, s2.query(Foo).all() # The Foo('B') object is *not* returned
# as part of this query because it hasn't
# been flushed yet.
s2.flush() # Now, Foo('B') is in the same state as
# Foo('A') was above.
print 3, s2.query(Foo).all()
s2.rollback() # Foo('B') has not been committed, and rolling
# back the session's transaction removes it
# from the session.
print 4, s2.query(Foo).all()
#---
Output:
1 [<Foo('A')>]
2 [<Foo('A')>]
3 [<Foo('A')>, <Foo('B')>]
4 [<Foo('A')>]
session.query()
danach machesession.flush()
, werde ich meine Änderungen sehen? Vorausgesetzt, ich benutze MyISAM.flush()
undcommit()
oder sollte ich das der Alchemie überlassen? Ich habe esflush()
in einigen Fällen verwendet, weil nachfolgende Abfragen neue Daten abrufen mussten.autoflush
(True
standardmäßig). Es wird automatisch vor allen Abfragen gelöscht, sodass Sie sich nicht jedes Mal daran erinnern müssen.Wie @snapshoe sagt
Wann
session.autocommit == False
:commit()
wird anrufen,flush()
wenn Sie einstellenautoflush == True
.Wann
session.autocommit == True
:Sie können nicht anrufen,
commit()
wenn Sie keine Transaktion gestartet haben (was Sie wahrscheinlich nicht getan haben, da Sie diesen Modus wahrscheinlich nur verwenden würden, um die manuelle Verwaltung von Transaktionen zu vermeiden).In diesem Modus müssen Sie anrufen
flush()
, um Ihre ORM-Änderungen zu speichern. Der Flush schreibt effektiv auch Ihre Daten fest.quelle
autoflush
Parameter steuert, ob sqlalchemy zuerst einen Flush ausgibt, wenn vor dem Ausgeben einer Abfrage ausstehende Schreibvorgänge vorhanden sind, und hat nichts mit der Steuerung des unvermeidlichen Flushs beim Festschreiben zu tun.Warum spülen, wenn Sie sich verpflichten können?
Als jemand, der neu in der Arbeit mit Datenbanken und SQLalchemie ist, waren mir die vorherigen Antworten, die
flush()
SQL-Anweisungen an die Datenbank senden und diese beibehalten,commit()
nicht klar. Die Definitionen sind sinnvoll, aber aus den Definitionen geht nicht sofort hervor, warum Sie einen Flush verwenden würden, anstatt nur einen Commit durchzuführen.Da ein Commit immer gelöscht wird ( https://docs.sqlalchemy.org/en/13/orm/session_basics.html#committing ), klingen diese sehr ähnlich. Ich denke, das große Problem ist, dass ein Flush nicht permanent ist und rückgängig gemacht werden kann, während ein Commit permanent ist, in dem Sinne, dass Sie die Datenbank nicht bitten können, das letzte Commit rückgängig zu machen (glaube ich).
@snapshoe hebt hervor, dass Sie, wenn Sie die Datenbank abfragen und Ergebnisse mit neu hinzugefügten Objekten erhalten möchten, zuerst geleert haben müssen (oder festgeschrieben haben müssen, was für Sie geleert wird). Vielleicht ist dies für einige Leute nützlich, obwohl ich nicht sicher bin, warum Sie lieber spülen als festschreiben möchten (abgesehen von der trivialen Antwort, dass es rückgängig gemacht werden kann).
In einem anderen Beispiel habe ich Dokumente zwischen einer lokalen Datenbank und einem Remote-Server synchronisiert. Wenn der Benutzer den Vorgang abbrechen möchte, sollten alle Hinzufügungen / Aktualisierungen / Löschungen rückgängig gemacht werden (dh keine teilweise Synchronisierung, nur eine vollständige Synchronisierung). Beim Aktualisieren eines einzelnen Dokuments habe ich beschlossen, einfach die alte Zeile zu löschen und die aktualisierte Version vom Remote-Server hinzuzufügen. Es stellt sich heraus, dass aufgrund der Art und Weise, wie sqlalchemy geschrieben ist, die Reihenfolge der Operationen beim Festschreiben nicht garantiert ist. Dies führte dazu, dass eine doppelte Version hinzugefügt wurde (bevor versucht wurde, die alte zu löschen), was dazu führte, dass die Datenbank eine eindeutige Einschränkung nicht erfüllte. Um dies zu umgehen, habe ich verwendet,
flush()
damit die Reihenfolge beibehalten wurde, aber ich konnte es trotzdem rückgängig machen, wenn der Synchronisierungsprozess später fehlschlug.Siehe meinen Beitrag dazu unter: Gibt es eine Reihenfolge für das Hinzufügen oder Löschen beim Festschreiben in sqlalchemy?
In ähnlicher Weise wollte jemand wissen, ob beim Hinzufügen eine Reihenfolge hinzugefügt wird, dh wenn ich hinzufüge und
object1
dann hinzufügeobject2
, wirdobject1
sie der Datenbank hinzugefügt, bevorobject2
SQLAlchemy die Reihenfolge beim Hinzufügen von Objekten zur Sitzung speichert.Auch hier würde vermutlich die Verwendung eines Flush () das gewünschte Verhalten sicherstellen. Zusammenfassend lässt sich sagen, dass eine Verwendung für Flush darin besteht, Bestellgarantien bereitzustellen (glaube ich), während Sie sich dennoch eine "Rückgängig" -Option erlauben, die Commit nicht bietet.
Autoflush und Autocommit
Beachten Sie, dass das automatische Löschen verwendet werden kann, um sicherzustellen, dass Abfragen in einer aktualisierten Datenbank ausgeführt werden, da sqlalchemy vor dem Ausführen der Abfrage geleert wird. https://docs.sqlalchemy.org/en/13/orm/session_api.html#sqlalchemy.orm.session.Session.params.autoflush
Autocommit ist etwas anderes, das ich nicht vollständig verstehe, aber es scheint, als würde von seiner Verwendung abgeraten: https://docs.sqlalchemy.org/en/13/orm/session_api.html#sqlalchemy.orm.session.Session.params. Autocommit
Speichernutzung
Nun wollte die ursprüngliche Frage eigentlich wissen, wie sich Flush vs. Commit für Speicherzwecke auswirkt. Da die Fähigkeit zum Fortbestehen oder Nichtbestehen etwas ist, was die Datenbank bietet (glaube ich), sollte ein einfaches Leeren ausreichen, um in die Datenbank zu verlagern - obwohl das Festschreiben nicht schaden sollte (was wahrscheinlich hilft - siehe unten), wenn Sie sich nicht um das Rückgängigmachen kümmern .
sqlalchemy verwendet eine schwache Referenzierung für Objekte, die gelöscht wurden: https://docs.sqlalchemy.org/en/13/orm/session_state_management.html#session-referencing-behavior
Das heißt, wenn Sie ein Objekt nicht explizit an einem Ort haben, wie in einer Liste oder einem Diktat, wird es von sqlalchemy nicht gespeichert.
Dann müssen Sie sich jedoch um die Datenbankseite kümmern. Vermutlich ist das Löschen ohne Festschreiben mit einer Speicherstrafe verbunden, um die Transaktion aufrechtzuerhalten. Auch hier bin ich neu, aber hier ist ein Link, der genau dies zu suggerieren scheint: https://stackoverflow.com/a/15305650/764365
Mit anderen Worten, Commits sollten die Speichernutzung reduzieren, obwohl hier vermutlich ein Kompromiss zwischen Speicher und Leistung besteht. Mit anderen Worten, Sie möchten wahrscheinlich nicht jede einzelne Datenbankänderung einzeln festschreiben (aus Leistungsgründen), aber zu langes Warten erhöht die Speichernutzung.
quelle
Dies beantwortet nicht unbedingt die ursprüngliche Frage, aber einige Leute haben erwähnt, dass
session.autoflush = True
Sie nicht verwenden müssensession.flush()
... Und das ist nicht immer wahr.Wenn Sie die ID eines neu erstellten Objekts mitten in einer Transaktion verwenden möchten , müssen Sie aufrufen
session.flush()
.Dies liegt daran , dass die ID NICHT automatisch ausgefüllt wird (obwohl eine Abfrage des Objekts dies
autoflush
tut , was manchmal zu Verwirrung führen kann, wie in "Warum funktioniert das hier, aber nicht dort?", Aber Snapshoe hat diesen Teil bereits behandelt).Ein verwandter Aspekt, der mir ziemlich wichtig erscheint und nicht wirklich erwähnt wurde:
Warum würden Sie nicht die ganze Zeit begehen? - Die Antwort ist Atomizität .
Ein schickes Wort: Ein Ensemble von Operationen muss alle erfolgreich ausgeführt werden, oder keine von ihnen wird wirksam.
Wenn Sie beispielsweise ein Objekt (A) erstellen / aktualisieren / löschen und dann ein anderes Objekt (B) erstellen / aktualisieren / löschen möchten, aber (B) fehlschlagen möchten, möchten Sie (A) zurücksetzen. Dies bedeutet, dass diese beiden Operationen atomar sind .
Wenn (B) ein Ergebnis von (A) benötigt, möchten Sie daher
flush
nach (A) undcommit
nach (B) aufrufen .Außerdem müssen Sie nicht manuell anrufen
session.autoflush is True
, außer in dem Fall, den ich oben oder in Jimbos Antwort erwähnt habeflush
.quelle