SQLAlchemy: создание и повторное использование сеанса



просто быстрый вопрос: SQLAlchemy переговоры о вызов sessionmaker() один раз, но называть получившееся Session() класс каждый раз, когда вам нужно поговорить с вашей БД. Для меня это означает, что второй я бы сделал свой первый session.add(x) или что-то подобное, я бы сначала сделать



from project import Session
session = Session()


то, что я делал до сих пор, было сделать звонок session = Session() в моей модели после а затем всегда импортировать один и тот же сеанс в любом месте моего приложения. Поскольку это веб-приложения это обычно означает то же самое (как один вид выполняется).



но в чем же разница? В чем недостаток использования одного сеанса все время против использования его для моей базы данных, пока моя функция не будет выполнена, а затем создать новый в следующий раз, когда я хочу поговорить с моей БД?



Я понимаю, что если я использую несколько потоков, каждый из них должен получить свой собственный сеанс. Но с помощью scoped_session(), Я уже убедился, что эта проблема не существует, не так ли?



пожалуйста уточнить, если мои предположения ошибочны.

1656   3  

3 ответов:

sessionmaker() Это завод, он там, чтобы поощрять размещение параметров конфигурации для создания новых Session объекты в одном месте. Это необязательно, что можно просто позвонить Session(bind=engine, expire_on_commit=False) в любое время Вы нужен новый Session, за исключением того, что он многословен и избыточен, и я хотел остановить распространение мелких "помощников", которые каждый подходил к проблеме этой избыточности каким-то новым и более запутанным способом.

так sessionmaker() Это просто инструмент, который поможет вам создать Session объекты, когда они вам нужны.

Следующая часть. Я думаю, что вопрос в том, в чем разница между созданием нового Session() в различных точках по сравнению с просто использованием одного до конца. Ответ, не очень много. Session является контейнером для всех объектов, которые вы положили в него, а затем он также отслеживает открытой сделки. В данный момент Вы звоните rollback() или commit(), транзакция закончена, и Session не имеет подключения к базе данных, пока она не будет вызвана чтобы снова выдать SQL. Ссылки, которые он содержит на ваши сопоставленные объекты, являются слабыми ссылками, при условии, что объекты чисты от ожидающих изменений, поэтому даже в этом отношении Session будет опустошить себя обратно в совершенно новое состояние, когда ваше приложение теряет все ссылки на сопоставленные объекты. Если вы оставите его с его значением по умолчанию "expire_on_commit" установка, то все объекты истекли после фиксации. Если что Session болтается в течение пяти или двадцати минут, и все виды вещей изменились в базе данных в следующий раз, когда вы используете его, он загрузит все совершенно новое состояние при следующем доступе к этим объектам, даже если они сидели в памяти в течение двадцати минут.

в веб-приложениях, мы обычно говорим, Эй, почему бы вам не сделать новый Session на каждый запрос, а не использовать один и тот же снова и снова. Эта практика гарантирует, что новый запрос начинается "чистым". Если некоторые объекты из предыдущего запроса еще не были собраны в мусор, и если, возможно, вы повернули выкл "expire_on_commit", возможно, какое-то состояние из предыдущего запроса все еще висит вокруг, и это состояние может быть даже довольно старым. Если вы будете осторожны, чтобы уйти expire_on_commit включен и определенно позвонить commit() или rollback() в конце запроса, то это нормально, но если вы начинаете с совершенно нового Session, тогда даже нет никаких вопросов, что вы начинаете с чистого листа. Так что идея начинать каждый запрос с нового Session это действительно просто самый простой способ убедиться, что вы начинаете новый, и сделать использование expire_on_commit в значительной степени необязательно, так как этот флаг может нести много дополнительного SQL для операции, которая вызывает commit() в середине серии операций. Не уверен, что это ответ на ваш вопрос.

следующий раунд-это то, что вы упоминаете о многопоточности. Если ваше приложение многопоточное, мы рекомендуем убедиться, что Session используется локально...что-то. scoped_session() по умолчанию делает его локальным для текущего потока. В веб-приложении локальный запрос на самом деле еще лучше. Flask-SQLAlchemy фактически отправляет пользовательскую функцию "scope" в scoped_session() так что вы получите сеанс с областью запроса. Среднее приложение пирамиды вставляет сеанс в реестр" запрос". При использовании таких схем идея "создать новый сеанс по запросу" продолжает выглядеть как самый простой способ сохранить все прямо.

в дополнение к превосходному ответу zzzeek, вот простой рецепт для быстрого создания одноразовых, замкнутых сессий:

from contextlib import contextmanager

from sqlalchemy import create_engine
from sqlalchemy.orm import scoped_session, sessionmaker

@contextmanager
def db_session(db_url):
    """ Creates a context with an open SQLAlchemy session.
    """
    engine = create_engine(db_url, convert_unicode=True)
    connection = engine.connect()
    db_session = scoped_session(sessionmaker(autocommit=False, autoflush=True, bind=engine))
    yield db_session
    db_session.close()
    connection.close()

использование:

from mymodels import Foo

with db_session("sqlite://") as db:
    foos = db.query(Foo).all()

вы можете создать сеанс с помощью db

db = SQLAlchemy(app)
engine = db.engine
Session = sessionmaker(engine)
session = Session()

Comments

    Ничего не найдено.