2010-11-17 9 views
273

Jaka jest różnica między flush() a commit() w SQLAlchemy?SQLAlchemy: Jaka jest różnica między flush() i commit()?

Czytałem dokumenty, ale nie jestem mądrzejszy - wydają się zakładać wstępne zrozumienie, którego nie posiadam.

Jestem szczególnie zainteresowany ich wpływem na wykorzystanie pamięci. Ładuję niektóre dane do bazy danych z serii plików (łącznie około 5 milionów wierszy) i moja sesja czasami się przewraca - jest to duża baza danych i maszyna z niewielką ilością pamięci.

Zastanawiam się, czy używam zbyt wielu połączeń commit() i niewystarczających flush() - ale bez zrozumienia, jaka to różnica, trudno powiedzieć!

Odpowiedz

334

Obiekt sesji jest zasadniczo bieżącą transakcją zmian w bazie danych (aktualizacja, wstawianie, usuwanie). Operacje te nie są przechowywane w bazie danych dopóki nie zostaną zatwierdzone (jeśli program zostanie przerwany z jakiegoś powodu w transakcji w połowie sesji, wszelkie niezatwierdzone zmiany w nim zostaną utracone).

Obiekt sesji rejestruje operacje transakcji z session.add(), ale nie przekazuje jeszcze ich do bazy danych do czasu wywołania session.flush().

session.flush() przekazuje serię operacji do bazy danych (wstaw, zaktualizuj, usuń). Baza danych utrzymuje je jako oczekujące operacje w transakcji. Zmiany nie są trwale przechowywane na dysku lub widoczne dla innych transakcji, dopóki baza danych nie otrzyma polecenia COMMIT dla bieżącej transakcji (co robi session.commit()).

session.commit() zatwierdza (utrzymuje) te zmiany w bazie danych.

flush() jest zawsze nazywane jako część zaproszenia do commit() (1).

Podczas korzystania z obiektu Session do wysyłania zapytań do bazy danych, zapytanie zwróci wyniki zarówno z bazy danych, jak iz spłukanej części niezatrzymanej transakcji, którą posiada. Domyślnie obiekty sesji autoflush ich operacje, ale można to wyłączyć.

Mam nadzieję, że w tym przykładzie będzie to jaśniej:

#--- 
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')>] 
+0

Jeszcze jedna rzecz: czy wiesz, czy wywołanie funkcji commit() zwiększa używaną pamięć, czy ją zmniejsza? – AP257

+2

Jest to również wartość false dla silników db, które nie obsługują transakcji, takich jak myisam. Ponieważ nie ma trwającej transakcji, flush ma jeszcze mniej, aby odróżnić się od commit. – underrun

+0

@underrun Więc jeśli zrobię 'session.query()' po 'session.flush()', czy zobaczę moje zmiany? Biorąc pod uwagę, używam MyISAM. –

9

Jak @snapshoe mówi

flush() wysyła swoich zapytań SQL do bazy danych

commit() zatwierdza transakcję.

Kiedy session.autocommit == fałsz:

commit() wywoła flush(), jeśli autoflush == true.

Po sesji.autocommit == True:

Nie można wywołać metody commit(), jeśli nie rozpoczęto transakcji (co prawdopodobnie nie nastąpiło, ponieważ prawdopodobnie używałbyś tego trybu tylko w celu uniknięcia ręcznego zarządzania transakcjami).

W tym trybie należy wywołać funkcję flush(), aby zapisać zmiany ORM. Efekt flush skutecznie angażuje również Twoje dane.

Powiązane problemy