Как бороться с политикой блокировки таблиц БД sqlalchemy? - PullRequest
0 голосов
/ 08 февраля 2011

Может кто-нибудь объяснить, как я могу избежать зависания приложения, когда у меня, например, есть список сущностей и возможность переходить на страницы с подробностями. Итак, я открываю список, и начинается один сеанс sqlalchemy, затем я открываю одну страницу с подробностями, а затем - другую, затем еще одну и приложение замораживается, потому что один сеанс блокирует другой. Я не могу использовать один сеанс для всего приложения, потому что тогда я не могу сказать, что что-то было отредактировано в форме, просто проверяя session.dirty, новые, удаленные атрибуты и обработка состояния приложения становится адом хрупкого нечитаемого кода.

Нужно ли реализовывать какую-то другую политику обработки сеансов? Нужно ли настраивать sqlalchemy mapping или sql server?

Вот минимальный рабочий пример:

from sqlalchemy import MetaData, Table, Column, FetchedValue, ForeignKey, create_engine
from sqlalchemy.types import BigInteger, String
from sqlalchemy.orm import mapper, relationship, sessionmaker, Session

class Ref(object):
    id = None
    name = None
    id_parent = None

class TableMapper(object):

    def __init__(self, metadata, mapped_type):
        self._table = None
        self._mapped_type = mapped_type

    def get_table(self):
        return self._table

    def set_table(self, table):
        assert isinstance(table, Table)
        self._table = table

class RefTableMapper(TableMapper):

    def __init__(self, metadata):
        TableMapper.__init__(self, metadata, Ref)
        self.set_table(Table('Ref', metadata,
                             Column('id', BigInteger,
                                    primary_key = True, nullable = False),
                             Column('name', String),
                             Column('id_parent', BigInteger,
                                    ForeignKey('Ref.id'))
                             ))
    def map_table(self):
        r_parent = relationship(Ref,
                            uselist = False,
                            remote_side = [self._table.c.id],
                            primaryjoin = (
                                self._table.c.id_parent == self._table.c.id))
        mapper(Ref, self._table,
               properties = {'parent': r_parent})
        return self._table

class Mapper(object):

    def __init__(self, url, echo = False):
        self._engine = create_engine(url, echo = echo)
        self._metadata = MetaData(self._engine)
        self._Session = sessionmaker(bind = self._engine, autoflush = False)
        ref_t = RefTableMapper(self._metadata).map_table()

    def create_session(self):
        return self._Session()

if __name__ == '__main__':
    mapp = Mapper(r'mssql://username:pwd@Server\SQLEXPRESS/DBName', True)
    s = mapp.create_session()

    rr = s.query(Ref).all()

    s1 = mapp.create_session()
    merged = s1.merge(rr)
    merged.flush()

    s2 = mapp.create_session()
    rr1 = s2.query(Ref).all() #application freezes! 

1 Ответ

1 голос
/ 08 февраля 2011

Режим изоляции SQL Server по умолчанию блокирует целые таблицы очень агрессивно.(В приведенном выше примере кажется, что вы, возможно, отправляете UPDATE, а затем отправляете SELECT в другой транзакции, в то время как предыдущая транзакция находится в состоянии ожидания, хотя session.merge () не принимает список, а содержимое таблицы не указано вышепоэтому трудно сказать).

Во всяком случае, это обычная практика, включающая управление многовариантным параллелизмом (SQL-сервер называет это «версиями строк»), чтобы иметь разумную возможность блокировать отдельные строки друг против друга вместополные таблицы:

ALTER DATABASE MyDatabase SET ALLOW_SNAPSHOT_ISOLATION ON

ALTER DATABASE MyDatabase SET READ_COMMITTED_SNAPSHOT ON

Подробная информация об этом доступна в http://msdn.microsoft.com/en-us/library/ms175095.aspx.

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