2011-02-08 70 views
0

有人可以解釋一下,我如何避免應用程序凍結,例如,當我有一個實體列表並且能夠移動到詳細頁面時。 因此,我打開列表,然後開始一個sqlalchemy會話,然後打開一個詳細信息頁面,然後另一個詳細信息頁面,另一個詳細信息頁面,另一個詳細信息頁面和應用程序凍結,因爲一個會話會阻止另一個會話。 我不能使用一個會話整個應用程序,因爲我不能說,只是檢查session.dirty,新的,刪除的屬性和應用程序狀態處理變成了脆弱的不可讀代碼的地獄,在窗體上編輯了某些東西。如何處理sqlalchemy的數據庫表格阻止策略?

我是否需要實施一些其他類型的會話處理策略? 我是否需要調整sqlalchemy映射或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:[email protected]\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

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