SQLAlchemy: Какая разница между flush() и commit()?

В чем разница между flush() и commit() в SQLAlchemy?

Я читал документы, но не мудрее - они, кажется, предполагают предварительное понимание, которого у меня нет.

Меня особенно интересует их влияние на использование памяти. Я загружаю некоторые данные в базу данных из ряда файлов (всего около 5 миллионов строк), и моя сессия иногда падает - это большая база данных и машина с небольшим объемом памяти.

Мне интересно, использую ли я слишком много вызовов commit() и недостаточно вызовов flush() - но без реального понимания того, в чем разница, трудно сказать!

Ответ 1

Объект Session - это в основном текущая транзакция изменений в базе данных (обновление, вставка, удаление). Эти операции не сохраняются в базе данных до тех пор, пока они не будут зафиксированы (если ваша программа прерывается по какой-либо причине во время транзакции в середине сеанса, все незафиксированные изменения внутри нее теряются).

Сеансовый объект регистрирует транзакции с помощью session.add(), но еще не передает их в базу данных, пока не будет вызван session.flush().

session.flush() передает серию операций в базу данных (вставка, обновление, удаление). База данных поддерживает их как ожидающие операции в транзакции. Изменения не сохраняются на диске постоянно или не видны другим транзакциям до тех пор, пока база данных не получит COMMIT для текущей транзакции (что делает session.commit()).

session.commit() фиксирует (сохраняет) эти изменения в базе данных.

flush() всегда вызывается как часть вызова commit() (1).

Когда вы используете объект Session для запроса к базе данных, запрос будет возвращать результаты как из базы данных, так и из очищенных частей незафиксированной транзакции, которую он содержит. По умолчанию объекты Session autoflush свои операции, но это можно отключить.

Надеюсь, этот пример прояснит ситуацию:

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

Ответ 2

Как говорит @snapshoe

flush() отправляет ваши операторы SQL в базу данных

commit() commits the transaction.

Когда session.autocommit == False:

commit() вызовет flush(), если вы установите autoflush == True.

Когда session.autocommit == True:

Вы не можете позвонить в commit(), если не начали транзакцию (чего вы, вероятно, не сделали, поскольку вы, вероятно, использовали бы этот режим только для того, чтобы избежать ручного управления транзакциями).

В этом режиме вы должны позвонить в flush(), чтобы сохранить изменения ORM. Флеш эффективно также фиксирует ваши данные.