Obiekt sesji jest w zasadzie ciągłą transakcją zmian w bazie danych (aktualizacja, wstawianie, usuwanie). Operacje te nie są utrwalane w bazie danych, dopóki nie zostaną zatwierdzone (jeśli program z jakiegoś powodu przerywa transakcję w trakcie sesji, wszelkie niezatwierdzone zmiany zostają utracone).
Obiekt sesji rejestruje operacje transakcji session.add()
, ale jeszcze nie komunikuje ich z bazą danych, dopóki nie session.flush()
zostanie wywołana.
session.flush()
przesyła szereg operacji do bazy danych (wstawianie, aktualizowanie, usuwanie). Baza danych utrzymuje je jako operacje oczekujące w transakcji. Zmiany nie są trwale zapisywane na dysku ani widoczne dla innych transakcji, dopóki baza danych nie otrzyma instrukcji COMMIT dla bieżącej transakcji (co się session.commit()
dzieje).
session.commit()
zatwierdza (utrzymuje) te zmiany w bazie danych.
flush()
jest zawsze wywoływany jako część połączenia z commit()
( 1 ).
Gdy użyjesz obiektu Session do zapytania do bazy danych, zapytanie zwróci wyniki zarówno z bazy danych, jak i z wypłukanych części niezatwierdzonej transakcji, którą przechowuje. Domyślnie Session sprzeciwia się autoflush
ich działaniu, ale można to wyłączyć.
Mam nadzieję, że ten przykład uczyni to bardziej zrozumiałym:
#---
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()
późniejsession.flush()
, czy zobaczę moje zmiany? Biorąc pod uwagę, że używam MyISAM.flush()
icommit()
czy powinienem pozostawić to Alchemii. Używałemflush()
w niektórych przypadkach, ponieważ kolejne zapytania wymagały pobrania nowych danych.autoflush
(True
domyślnie). Spłuka się automatycznie przed wszystkimi zapytaniami, więc nie musisz za każdym razem pamiętać.Jak mówi @snapshoe
Kiedy
session.autocommit == False
:commit()
zadzwoni,flush()
jeśli ustawiszautoflush == True
.Kiedy
session.autocommit == True
:Nie możesz zadzwonić,
commit()
jeśli nie rozpocząłeś transakcji (czego prawdopodobnie nie zrobiłeś, ponieważ prawdopodobnie użyłbyś tego trybu tylko w celu uniknięcia ręcznego zarządzania transakcjami).W tym trybie musisz zadzwonić,
flush()
aby zapisać zmiany ORM. Opróżnianie skutecznie zatwierdza również twoje dane.źródło
autoflush
kontroluje, czy sqlalchemy najpierw wyda kolor, jeśli istnieją oczekujące zapisy przed wydaniem zapytania i nie ma nic wspólnego z kontrolowaniem nieuniknionego koloru przy zatwierdzeniu.Po co spłukiwać, jeśli możesz popełnić?
Jako ktoś nowy w pracy z bazami danych i sqlalchemy, poprzednie odpowiedzi - które
flush()
wysyłają instrukcje SQL do bazy danych icommit()
nadal je trwają - nie były dla mnie jasne. Definicje mają sens, ale z definicji nie wynika jasno, dlaczego miałbyś używać koloru zamiast po prostu zatwierdzać.Ponieważ zatwierdzenie zawsze się opróżnia ( https://docs.sqlalchemy.org/en/13/orm/session_basics.html#committing ), brzmią bardzo podobnie. Myślę, że główną kwestią do podkreślenia jest to, że kolor nie jest trwały i można go cofnąć, podczas gdy zatwierdzenie jest trwałe, w tym sensie, że nie można poprosić bazy danych o cofnięcie ostatniego zatwierdzenia (myślę)
@snapshoe podkreśla, że jeśli chcesz wykonać zapytanie do bazy danych i uzyskać wyniki, które zawierają nowo dodane obiekty, musisz najpierw wyczyścić (lub zatwierdzić, co będzie dla ciebie opróżniać). Być może jest to przydatne dla niektórych osób, chociaż nie jestem pewien, dlaczego miałbyś chcieć spłukać zamiast zatwierdzić (oprócz trywialnej odpowiedzi, że można to cofnąć).
W innym przykładzie synchronizowałem dokumenty między lokalną bazą danych a zdalnym serwerem i jeśli użytkownik zdecydował się anulować, wszystkie dodania / aktualizacje / usunięcia powinny zostać cofnięte (tzn. Brak częściowej synchronizacji, tylko pełna synchronizacja). Podczas aktualizacji jednego dokumentu postanowiłem po prostu usunąć stary wiersz i dodać zaktualizowaną wersję ze zdalnego serwera. Okazuje się, że ze względu na sposób pisania sqlalchemy kolejność operacji podczas zatwierdzania nie jest gwarantowana. Doprowadziło to do dodania zduplikowanej wersji (przed próbą usunięcia starej), co spowodowało, że baza danych nie wykonała unikalnego ograniczenia. Aby obejść ten problem, użyłem
flush()
, aby zachować porządek, ale nadal mogłem cofnąć, jeśli później proces synchronizacji się nie powiedzie.Zobacz mój post na ten temat na stronie: Czy istnieje zamówienie na dodawanie kontra usuwanie podczas zatwierdzania w sqlalchemy
Podobnie, ktoś chciał wiedzieć, czy kolejność dodawania jest zachowywana podczas zatwierdzania, tj. Jeśli dodam,
object1
a potem dodamobject2
, czyobject1
zostanie dodana do bazy danych wcześniej.object2
Czy SQLAlchemy zapisuje kolejność podczas dodawania obiektów do sesji?Ponownie, tutaj prawdopodobnie użycie flush () zapewniłoby pożądane zachowanie. Podsumowując, jednym z zastosowań flush jest zapewnienie gwarancji zamówień (tak myślę), jednocześnie nadal pozwalając sobie na opcję cofania, której nie zapewnia zatwierdzenie.
Autoflush i Autocommit
Uwaga: można użyć funkcji automatycznego czyszczenia, aby upewnić się, że zapytania działają na zaktualizowanej bazie danych, ponieważ sqlalchemy opróżni się przed wykonaniem zapytania. https://docs.sqlalchemy.org/en/13/orm/session_api.html#sqlalchemy.orm.session.Session.params.autoflush
Autocommit to coś, czego nie do końca rozumiem, ale wygląda na to, że nie zaleca się jego używania: https://docs.sqlalchemy.org/en/13/orm/session_api.html#sqlalchemy.orm.session.Session.params. automatyczne zatwierdzanie
Zużycie pamięci
Teraz pierwotne pytanie naprawdę chciało wiedzieć o wpływie koloru do zatwierdzenia dla celów pamięci. Ponieważ zdolność do utrzymywania się lub nie jest czymś, co oferuje baza danych (myślę), zwykłe opróżnianie powinno wystarczyć do odciążenia bazy danych - chociaż popełnienie nie powinno zaszkodzić (faktycznie prawdopodobnie pomaga - patrz poniżej), jeśli nie obchodzi cię cofnięcie .
sqlalchemy używa słabego odwołania do obiektów, które zostały opróżnione: https://docs.sqlalchemy.org/en/13/orm/session_state_management.html#session-referencing-behavior
Oznacza to, że jeśli nie masz obiektu gdzieś wyraźnie trzymanego, np. Na liście lub w dykcie, sqlalchemy nie zachowa go w pamięci.
Masz jednak bazę danych rzeczy do zmartwienia. Przypuszczalnie opróżnienie bez popełnienia wiąże się z pewną karą pamięci, aby utrzymać transakcję. Znów jestem nowy, ale tutaj jest link, który sugeruje dokładnie to: https://stackoverflow.com/a/15305650/764365
Innymi słowy, zatwierdzenia powinny zmniejszyć zużycie pamięci, chociaż przypuszczalnie istnieje tutaj kompromis między pamięcią a wydajnością. Innymi słowy, prawdopodobnie nie chcesz zatwierdzać każdej zmiany bazy danych, pojedynczo (ze względu na wydajność), ale zbyt długie oczekiwanie zwiększy użycie pamięci.
źródło
To nie odpowiada ściśle na pierwotne pytanie, ale niektórzy wspominali, że przy
session.autoflush = True
tobie nie musisz używaćsession.flush()
... I to nie zawsze jest prawdą.Jeśli chcesz użyć identyfikatora nowo utworzonego obiektu w środku transakcji , musisz wywołać
session.flush()
.Wynika to z tego,
autoflush
że NIE automatycznie wypełnia identyfikator (chociaż zapytanie o obiekt będzie, co czasami może powodować zamieszanie, np. „Dlaczego to działa tutaj, ale nie tam?” Ale snapshoe już obejmuje tę część).Jeden powiązany aspekt, który wydaje mi się bardzo ważny i nie został tak naprawdę wspomniany:
Dlaczego nie popełniasz cały czas? - Odpowiedzią jest atomowość .
Fantazyjny słowo powiedzieć: to zespół działań muszą wszyscy być wykonana pomyślnie albo żaden z nich nie przyniosą efektu.
Na przykład, jeśli chcesz utworzyć / zaktualizować / usunąć jakiś obiekt (A), a następnie utworzyć / zaktualizować / usunąć inny obiekt (B), ale jeśli (B) się nie powiedzie, chcesz przywrócić (A). Oznacza to, że te 2 operacje są atomowe .
Dlatego jeśli (B) potrzebuje wyniku (A), chcesz wywoływać
flush
po (A) icommit
po (B).Ponadto, jeśli
session.autoflush is True
, z wyjątkiem przypadku, o którym wspomniałem powyżej lub innych w odpowiedzi Jimbo , nie będziesz musiał dzwonićflush
ręcznie.źródło