sqlalchemy:访问model.id commit时的objectDeletedError,为什么



它有时会发生在我的产品env上(大多数时候可以)。我怀疑这是否与SessionMaker func

中的参数" Expire_on_commit"有关
@close_session
def func():
    session = DBSession() # scoped_session, thread_local
    m = Model()
    m.content = 'content'
    session.add(m)
    try:
        session.commit()
    except SQLAlchemyError as e:
        session.rollback()
        raise_my_exception()
    return m.id

Close_session是一种装饰器,将在"最后"部分中进行'dbsession()。close()'''。objectDeleteError发生在中的"返回m.id"

sqlalchemy配置:

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))

objectDeletedError doc:

class ObjectDeletedError(sqlalchemy.exc.InvalidRequestError)
 |  A refresh operation failed to retrieve the database
 |  row corresponding to an object's known primary key identity.
 | 
 |  A refresh operation proceeds when an expired attribute is
 |  accessed on an object, or when :meth:`.Query.get` is
 |  used to retrieve an object which is, upon retrieval, detected
 |  as expired.   A SELECT is emitted for the target row
 |  based on primary key; if no row is returned, this
 |  exception is raised.
 | 
 |  The true meaning of this exception is simply that
 |  no row exists for the primary key identifier associated
 |  with a persistent object.   The row may have been
 |  deleted, or in some cases the primary key updated
 |  to a new value, outside of the ORM's management of the target
 |  object.
 |  

编辑:我将"返回m.id"放在" session.commit()"之后," objectDeletereder"仍在升高

@close_session
def func():
    session = DBSession() # scoped_session, thread_local
    m = Model()
    m.content = 'content'
    session.add(m)
    try:
        session.commit()
        return m.id
    except SQLAlchemyError as e:
        session.rollback()
        raise_my_exception()

edit2:

我更改了我的路由,只返回大师,错误消失了:

class RoutingSession(Session):                                                     
    def get_bind(self, mapper=None, clause=None):                                  
        return engines['master']                                                               

因此,它必须与此主/从配置有关。

关于如何解决的想法?

使用默认值(expire_on_commit = true)创建dbsession。因此,在承诺后,当返回OBJ.ID时,OBJ已过期。因此,会话将从从属数据库(引擎['从'])中获取OBJ,但是由于主奴隶延迟,相应的记录尚未同步到从。

此错误意味着两件事之一:

  1. rise_my_exception()实际上并未提高异常,因此在回滚()中,代码落入" return m.id"中,并且该行不存在,因为它被回滚。

    <。
  2. 在您说Session.commit()和" return M.ID"的时间之间,并发线程或过程正在删除行。数据将从提交后的" M"过期,因此下一个访问将将该对象的最新数据从数据库中检索到新事务中。这与您的描述是一致的:"有时(大多数时候可以)"。 - 一个仅偶尔发生的问题通常是由于并发问题。

相关内容

  • 没有找到相关文章

最新更新