Проблемы с scoped_session в sqlalchemy - как это работает? - PullRequest
6 голосов
/ 30 августа 2009

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

В любом случае проблема заключается в следующем:

S = elixir.session # = scoped_session(...)
f = Foo(bar=1)
S.add(f) # ERROR, f is already attached to session (different session)

Не уверен, как f оказался в другом сеансе, у меня не было проблем с этим раньше. В другом месте у меня есть код, который выглядит так же, но на самом деле работает. Как вы можете себе представить, я нахожу это очень запутанным.

Я просто ничего не знаю здесь, f, кажется, волшебным образом добавлен к сеансу в конструкторе, но у меня нет ссылок на сеанс, который он использует. Почему это закончится в другой сессии? Как я могу заставить это закончить в правильной сессии? Как все-таки работает эта функция scoped_session? Иногда кажется, что это работает, а иногда - нет.

Я определенно очень смущен.

Ответы [ 2 ]

7 голосов
/ 30 августа 2009

Сеанс Scoped создает прокси-объект, который ведет реестр (по умолчанию) для объектов сеанса потока, созданных по требованию из переданной фабрики сеансов. Когда вы обращаетесь к методу сеанса, например ScopedSession.add, он находит сеанс, соответствующий текущему потоку, и возвращает метод add, привязанный к этому сеансу. Активный сеанс можно удалить с помощью метода ScopedSession.remove().

ScopedSession имеет несколько удобных методов, один из них - query_property, который создает свойство, которое возвращает объект запроса, связанный с сессией области действия, в которой он был создан, и класс, к которому он был получен. Другой - ScopedSession.mapper, который добавляет конструктор __init__(**kwargs) по умолчанию и по умолчанию добавляет созданные объекты в сеанс с областью действия, из которого был создан преобразователь. Это поведение может контролироваться с помощью ключевого аргумента save_on_init для картографа. ScopedSession.mapper устарела из-за именно той проблемы, о которой идет речь. Это один из случаев, когда философия Python «явное лучше, чем неявное» действительно применима. К сожалению, Elixir по-прежнему использует ScopedSession.mapper.

2 голосов
/ 30 августа 2009

Оказывается, эликсир устанавливает save-on-init = True для созданных картографов. Это может быть отключено:

using_mapper_options(save_on_init=False)

Это решает проблему. Престижность на #sqlalchemy для того, чтобы выяснить, что происходит немедленно. Хотя мне все еще интересно, как на самом деле работает scoped_session, поэтому, если кто-то ответит на это, он получит кредит за ответ на вопрос.

...