【问题标题】:Why SQLAlchemy Session.filter().update/delete raise read-only exception when using RoutingSession?为什么使用 RoutingSession 时 SQLAlchemy Session.filter().update/delete 会引发只读异常?
【发布时间】:2013-05-16 12:15:56
【问题描述】:

以下是我的配置,slave是只读的:

engines = {                                                                        
    'master': create_engine(                                                       
        settings.MASTER_URL, echo=settings.ECHO_SQL, pool_recycle=3600),           
    'slave': create_engine(                                                        
        settings.SLAVE_URL, echo=settings.ECHO_SQL, pool_recycle=3600),            
}                                                                                  


class RoutingSession(Session):                                                     
    def get_bind(self, mapper=None, clause=None):                                  
        #return engines['master']                                                  
        if self._flushing:                                                         
            return engines['master']                                               
        else:                                                                      
            return engines['slave']                                                

DBSession = scoped_session(sessionmaker(class_=RoutingSession))

当我这样做时:

s = DBSession()
#synchronize_session=False makes execution faster
s.query(Model).filter(Model.id == 1).delete(synchronize_session=False)
s.commit()

它引发了一个由于“只读”而无法删除的异常。

如何重写我的 RoutingSession 以使上述“删除”使用“主”数据库

---编辑1---

我做了更多的测试。上面的'delete'和下面的'delete'不同,RoutingSession会返回'master':

model = s.query(Model).filter(Model.id == 1).first()
s.delete(model)
s.commit()

【问题讨论】:

    标签: python mysql session sqlalchemy master-slave


    【解决方案1】:

    query.delete() 不是“刷新”的一部分,因此通常如果您使用routing session recipe,您希望实现using_bind() 并在像delete() 这样的操作之前调用它:

    class RoutingSession(Session):
    
        def get_bind(self, mapper=None, clause=None ):
            if self._name:
                return engines[self._name]
            else:
                # other cases here
    
        _name = None
        def using_bind(self, name):
            s = RoutingSession()
            vars(s).update(vars(self))
            s._name = name
            return s
    

    然后使用:

    Session().using_bind("master").query(Model1).delete()
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-08-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多