【问题标题】:how does SQLAlchemy InvalidRequestError('Transaction XXX is not on the active transaction list) happen?SQLAlchemy InvalidRequestError('Transaction XXX is not on the active transaction list) 是如何发生的?
【发布时间】:2012-12-07 18:39:23
【问题描述】:

最近我遇到了一个 SQLAlchemy InvalidRequestError。 错误日志显示:

InvalidRequestError: Transaction <sqlalchemy.orm.session.SessionTransaction object at
0x106830dd0> is not on the active transaction list

什么情况下会报这个错误???

-----编辑----

# the following two line actually in my decorator
s = Session()
s.add(model1)

# refer to <http://techspot.zzzeek.org/2012/01/11/django-style-database-routers-in-sqlalchemy/>
s2 = Session().using_bind('master')

model2 = s2.query(Model2).with_lockmode('update').get(1)
model2.somecolumn = 'new'

s2.commit() 

引发此异常

-----编辑2 -----

s = Session().using_bind('master')


model = Model(user_id=123456)
s.add(model)
s.flush() 
# here, raise the exception. 
# I add log in get_bind() of RoutingSession. when doing 'flush', the _name is None, and it returns engines['slave'].  
#If I use commit() instead of flush(), then it commits successfully

我将 using_bind 方法更改如下,效果很好。

def using_bind(self, name):
    self._name = name
    return self

上一个RoutingSession:

class RoutingSession(Session):
    _name = None                                                                                                                                                

    def get_bind(self, mapper=None, clause=None):   
        logger.info(self._name)         
        if self._name:                                                                           
            return engines[self._name]                                          
        elif self._flushing:                                                                                                                                                                                                                  
            logger.info('master')                                                  
            return engines['master']                                               
        else:                                                                      
            logger.info('slave')    
            return engines['slave']

    def using_bind(self, name):                              
        s = RoutingSession()                                                      
        vars(s).update(vars(self))   
        s._name = name                                                                    
        return s

【问题讨论】:

    标签: mysql session sqlalchemy


    【解决方案1】:

    这是一个永远不会发生的内部断言。如果您可能不正确地以并发方式使用 Session 或操纵其内部,那么至少没有完整的堆栈跟踪就无法回答这个问题。如果我操作与 Session 对象相关的私有方法或状态,我只能显示引发的异常。

    是这样的:

    from sqlalchemy.orm import Session
    
    s = Session()
    s2 = Session()
    
    t = s.transaction
    t2 = s2.transaction
    
    s2.transaction = t   # nonsensical assignment of the SessionTransaction
                         # from one Session to also be referred to by another,
                         # corrupts the transaction chain by leaving out "t2".
                         # ".transaction" should never be assigned to on the outside
    
    t2.rollback()  # triggers the assertion case
    

    基本上,上述情况永远不会发生,因为您不应该分配给“.transaction”。这是一个只读属性。

    【讨论】:

    • 嗨,zzzeek。我必须使用主会话(请参阅您文章中的示例)来锁定某些行。 (参见Edit2)并且再次引发异常。我不知道如何解决
    • 很可能是这样的:vars(s).update(vars(self))。使用 3rd 方库时,您不能只从其中一个对象中获取内部状态并将其推入另一个对象。该内部状态可以有任意数量的附件和依赖关系返回到父对象。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-30
    • 1970-01-01
    • 2019-12-31
    • 1970-01-01
    相关资源
    最近更新 更多