Объект 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'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()
послеsession.flush()
, я увижу свои изменения? Учитывая, что я использую MyISAM.flush()
иcommit()
, или я должен оставить это до алхимии. Я использовалflush()
в некоторых случаях, потому что последующие запросы должны были собрать новые данные.autoflush
(True
по умолчанию). Он автоматически сбрасывается перед всеми запросами, поэтому вам не нужно запоминать каждый раз.Как говорит @snapshoe
Когда
session.autocommit == False
:commit()
позвонит,flush()
если вы установитеautoflush == True
.Когда
session.autocommit == True
:Вы не можете позвонить,
commit()
если не начали транзакцию (чего вы, вероятно, не сделали, поскольку вы, вероятно, использовали бы только этот режим, чтобы избежать ручного управления транзакциями).В этом режиме вы должны позвонить,
flush()
чтобы сохранить изменения ORM. Флеш эффективно также фиксирует ваши данные.источник
autoflush
управляет тем, будет ли sqlalchemy сначала выдавать сброс, если имеются ожидающие записи перед выполнением запроса, и не имеет никакого отношения к управлению неизбежным сбросом при фиксации.Зачем флеш, если вы можете совершить?
Как кто-то новичок в работе с базами данных и sqlalchemy, предыдущие ответы - которые
flush()
отправляют операторы SQL в БД иcommit()
сохраняют их - были мне неясны. Определения имеют смысл, но из определений не сразу понятно, почему вы бы использовали сброс, а не просто фиксацию.Поскольку коммит всегда сбрасывается ( https://docs.sqlalchemy.org/en/13/orm/session_basics.html#committing ), эти звуки действительно похожи. Я думаю, что большая проблема, которую нужно подчеркнуть, заключается в том, что сброс не является постоянным и может быть отменен, тогда как фиксация является постоянной, в том смысле, что вы не можете попросить базу данных отменить последний коммит (я думаю)
@snapshoe подчеркивает, что если вы хотите запросить базу данных и получить результаты, которые включают вновь добавленные объекты, вам нужно сначала очистить (или зафиксировать, что для вас сбросит). Возможно, это полезно для некоторых людей, хотя я не уверен, почему вы хотели бы сбрасывать, а не фиксировать (кроме простого ответа, что его можно отменить).
В другом примере я синхронизировал документы между локальной БД и удаленным сервером, и если пользователь решил отменить, все добавления / обновления / удаления должны быть отменены (т. Е. Нет частичной синхронизации, только полная синхронизация). При обновлении одного документа я решил просто удалить старую строку и добавить обновленную версию с удаленного сервера. Оказывается, из-за способа написания sqlalchemy порядок операций при фиксации не гарантируется. Это привело к добавлению дублирующейся версии (перед попыткой удалить старую), что привело к тому, что БД не прошла уникальное ограничение. Чтобы обойти это, я использовал
flush()
так, чтобы порядок сохранялся, но я все еще мог отменить, если позже процесс синхронизации не удался.Смотрите мой пост по этому адресу: Есть ли порядок добавления или удаления при фиксации в sqlalchemy?
Точно так же кто-то хотел знать, поддерживается ли порядок добавления при фиксации, то есть, если я добавляю, а
object1
затем добавляюobject2
,object1
добавляется ли в базу данных раньшеobject2
Сохраняет ли SQLAlchemy порядок при добавлении объектов в сеанс?Опять же, здесь, вероятно, использование flush () обеспечит желаемое поведение. Таким образом, в общем, одно из применений для сброса - предоставить гарантии заказа (я думаю), опять же, при этом оставляя себе возможность «отменить», которую не предоставляет commit.
Автозапуск и Автокоммит
Обратите внимание, что autoflush может использоваться для обеспечения того, чтобы запросы действовали в обновленной базе данных, поскольку sqlalchemy будет сбрасываться перед выполнением запроса. https://docs.sqlalchemy.org/en/13/orm/session_api.html#sqlalchemy.orm.session.Session.params.autoflush
Autocommit - это еще кое-что, что я не совсем понимаю, но похоже, что его использование не рекомендуется: https://docs.sqlalchemy.org/en/13/orm/session_api.html#sqlalchemy.orm.session.Session.params. автокоммит
Использование памяти
Теперь первоначальный вопрос на самом деле хотел узнать о влиянии flush на commit для памяти. Поскольку способность сохранять или нет - это то, что предлагает база данных (я думаю), простой очистки должно быть достаточно для разгрузки базы данных - хотя фиксация не должна повредить (на самом деле, вероятно, помогает - см. Ниже), если вы не заботитесь об отмене ,
sqlalchemy использует слабые ссылки для сброшенных объектов: https://docs.sqlalchemy.org/en/13/orm/session_state_management.html#session-referencing-behavior
Это означает, что если у вас нет объекта, явно удерживаемого где-то, например, в списке или dict, sqlalchemy не будет хранить его в памяти.
Тем не менее, у вас есть проблемы с базой данных. Предположительно очистка без фиксации сопровождается некоторой потерей памяти для поддержки транзакции. Опять же, я новичок в этом, но вот ссылка, которая, кажется, предлагает именно это: https://stackoverflow.com/a/15305650/764365
Другими словами, коммиты должны уменьшить использование памяти, хотя, вероятно, здесь есть компромисс между памятью и производительностью. Другими словами, вы, вероятно, не хотите фиксировать каждое отдельное изменение базы данных, по одному (из соображений производительности), но слишком долгое ожидание увеличит использование памяти.
источник
Это не дает точного ответа на первоначальный вопрос, но некоторые люди упоминают, что с
session.autoflush = True
вами не нужно пользоватьсяsession.flush()
... И это не всегда так.Если вы хотите использовать идентификатор недавно созданного объекта в середине транзакции , вы должны позвонить
session.flush()
.Это потому,
autoflush
что НЕ выполняет автоматическое заполнение идентификатора (хотя запрос объекта будет, что иногда может вызвать путаницу, как в «почему это работает здесь, но не там?», Но Snapshoe уже охватил эту часть).Один связанный аспект, который кажется мне довольно важным и не был упомянут на самом деле:
Почему бы вам не совершить все время? - Ответ атомарность .
Причудливый слово сказать: ансамбль операций должны все быть выполнены успешно или ни один из них не вступит в силу.
Например, если вы хотите создать / обновить / удалить какой-либо объект (A), а затем создать / обновить / удалить другой (B), но если (B) не удалось, вы хотите вернуть (A). Это означает, что эти 2 операции являются атомарными .
Следовательно, если (B) нужен результат (A), вы хотите позвонить
flush
после (A) иcommit
после (B).Также, если
session.autoflush is True
, за исключением случая, который я упомянул выше или других в ответе Джимбо , вам не нужно будет звонитьflush
вручную.источник