Ответ 1
sessionmaker()
- это factory, чтобы поощрять размещение параметров конфигурации для создания новых объектов Session
только в одном месте. Это необязательно, так как вы могли бы просто вызвать Session(bind=engine, expire_on_commit=False)
в любое время, когда вам понадобится новый Session
, за исключением того, что он многословный и избыточный, и я хотел остановить распространение мелкомасштабных "помощников", к которым каждый обратился к проблеме этой избыточности в какой-то новой и более запутанной форме.
Итак, sessionmaker()
- это просто инструмент, который поможет вам создавать объекты Session
, когда они вам понадобятся.
Следующая часть. Я думаю, что вопрос в том, какая разница между созданием нового Session()
в разных точках и просто использованием всего этого. Ответ, не очень. Session
- это контейнер для всех объектов, которые вы вставляете в него, а затем он также отслеживает открытую транзакцию. В настоящий момент вы вызываете rollback()
или commit()
, транзакция завершена, а Session
не имеет подключения к базе данных, пока она не будет вызвана для повторного выпуска SQL. Ссылки, которые он связывает с вашими сопоставленными объектами, являются слабыми ссылками, если объекты чисты от ожидающих изменений, поэтому даже в этом случае Session
снова выйдет из себя в совершенно новое состояние, когда ваше приложение теряет все ссылки на сопоставленные объекты. Если вы оставите его с настройкой по умолчанию "expire_on_commit"
, то все объекты истек после фиксации. Если этот Session
зависает в течение пяти или 20 минут, и всевозможные вещи изменились в базе данных при следующем использовании, он будет загружать все новое состояние при следующем доступе к этим объектам, даже если они были сидя в памяти в течение двадцати минут.
В веб-приложениях мы обычно говорим: "Почему бы вам не сделать новый Session
по каждому запросу, а не использовать один и тот же снова и снова. Эта практика гарантирует, что новый запрос начнется" чистым". Если некоторые объекты из предыдущего запроса еще не были собраны в мусор, и, возможно, вы отключили "expire_on_commit"
, возможно, некоторое состояние из предыдущего запроса все еще висит вокруг, и это состояние может быть даже довольно старым. Если вы стараетесь оставить expire_on_commit
включенным и определенно называть commit()
или rollback()
по завершении запроса, то это хорошо, но если вы начинаете с нового Session
, тогда нет даже вопроса, который вы начинаете чистку. Таким образом, идея начать каждый запрос с помощью нового Session
- это просто самый простой способ убедиться, что вы начинаете свежие, и сделать использование expire_on_commit
довольно необязательным, так как этот флаг может нести много лишних SQL для операции, которая вызывает commit()
в середине последовательности операций. Не уверен, что это отвечает на ваш вопрос.
Следующий раунд - это то, о чем вы упоминаете о потоковом использовании. Если ваше приложение многопоточно, мы рекомендуем убедиться, что используемый Session
локальный для... что-то. scoped_session()
по умолчанию делает его локальным для текущего потока. В веб-приложении локальный запрос действительно даже лучше. Flask-SQLAlchemy фактически отправляет настраиваемую "функцию области видимости" на scoped_session()
, чтобы получить сеанс с охватом запросов. Среднее приложение Pyramid вставляет сеанс в реестр "запрос". При использовании подобных схем идея "создать новый сеанс по запросу" по-прежнему выглядит как самый простой способ держать вещи в чистоте.