Каков рекомендуемый шаблон использования scoped_session в многопоточном веб-приложении sqlalchemy? - PullRequest
26 голосов
/ 05 апреля 2011

Я пишу приложение с python и sqlalchemy-0.7.Он начинается с инициализации sqlalchemy orm (с использованием декларативного), а затем запускает многопоточный веб-сервер - в настоящее время я использую web.py для быстрого прототипирования, но это может измениться в будущем.Я также добавлю другие «потоки» для запланированных заданий и т. Д., Возможно, с использованием других потоков Python.

Из документации SA я понимаю, что мне нужно использовать scoped_session () для получения локального сеанса потока, поэтому мой вебПриложение .py должно выглядеть примерно так:

import web
from myapp.model import Session  # scoped_session(sessionmaker(bind=engine))
from myapp.model import This, That, AndSoOn
urls = blah...
app  = web.application(urls, globals())

class index:
    def GET(self):
        s = Session()
        # get stuff done
        Session().remove()
        return(stuff)

class foo:
    def GET(self):
        s = Session()
        # get stuff done
        Session().remove()
        return(stuff)

Это правильный путь для обработки сеанса?

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

Кроме того, я должен вызвать .remove () или .commit () или что-то вроде них на каждом конце метода, иначе сеанс будет по-прежнему содержать Постоянные объекты, и я не смогу запрашивать / получать доступ к тем же объектам в других потоках?

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

Ответы [ 2 ]

20 голосов
/ 18 июля 2012

Да, это правильный путь.

Пример:

Микрофрейм Flask с расширением Flask-sqlalchemy делает то, что вы описали Он также выполняет .remove () автоматически в конце каждого HTTP-запроса (функции «просмотра»), поэтому сеанс освобождается текущим потоком. Вызова просто .commit () недостаточно, вы должны использовать .remove ().

Когда я не использую представления Flask, я обычно использую оператор with:

@contextmanager
def get_db_session():
    try:
        yield session
    finally:
        session.remove()

with get_db_session() as session:
    # do something with session

Вы можете создать похожий декоратор.

Сеанс Scoped создает пул соединений с СУБД, поэтому этот подход будет быстрее, чем открытие / закрытие сеанса при каждом HTTP-запросе. Это также хорошо работает с гринлетами (gevent или eventlet).

2 голосов
/ 05 апреля 2011

Вам не нужно создавать сессию с заданной областью, если вы создаете новую сессию для каждого запроса, и каждый запрос обрабатывается одним потоком.

Вам нужно вызвать s.commit(), чтобы сделать ожидающим объекты постоянные , то есть для сохранения изменений в базе данных.

Вы также можете закрыть сеанс, вызвав s.close().

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...