【问题标题】:Why does SQLAlchemy/mysql keep timing out on me?为什么 SQLAlchemy/mysql 总是对我超时?
【发布时间】:2014-05-18 20:22:50
【问题描述】:

我有 2 个函数需要执行,第一个函数需要大约 4 个小时才能执行。两者都使用 SQLAlchemy:

def first():
    session = DBSession
    rows = session.query(Mytable).order_by(Mytable.col1.desc())[:150] 
    for i,row in enumerate(rows):
        time.sleep(100)
    print i, row.accession

def second():
    print "going onto second function"
    session = DBSession
    new_row = session.query(Anothertable).order_by(Anothertable.col1.desc()).first() 
    print 'New Row: ', new_row.accession


first()
second()

这是我定义 DBSession 的方式:

from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import scoped_session, sessionmaker
from sqlalchemy import create_engine

engine = create_engine('mysql://blah:blah@blah/blahblah',echo=False,pool_recycle=3600*12)
DBSession = scoped_session(sessionmaker(autocommit=False, autoflush=False, bind=engine))
Base = declarative_base()    
Base.metadata.bind = engine   

first() 完成得很好(大约需要 4 小时),我看到打印了“进入第二个函数”,然后它立即给我一个错误:

sqlalchemy.exc.OperationalError: (OperationalError) (2006, 'MySQL server has gone away')

通过阅读文档,我认为分配 session=DBSession 会得到两个不同的会话实例,因此 second() 不会超时。我也试过玩 pool_recycle ,这似乎没有任何效果。在现实世界中,我无法将 first() 和 second() 拆分为 2 个脚本:second() 必须在 first() 之后立即执行

【问题讨论】:

  • 我不知道您为什么会收到此错误,但我想指出,使用 scoped_session 您将收到完全相同的 Session 实例。请在Contextual/Thread-local Sessions 文档页面上阅读更多信息。但是,如果您不能拆分first()second(),我认为它们必须在同一个事务中运行(必须是atomic)。

标签: python mysql sqlalchemy


【解决方案1】:

您的引擎(不是会话)保留一个连接池。当 mysql 连接数小时未使用时,mysql 服务器会关闭套接字,这会在您尝试使用此连接时导致“Mysql 服务器已消失”错误。如果你有一个简单的单线程脚本,那么用pool_size=1 调用create_engine 可能会成功。如果没有,您可以在从池中检出连接时使用事件来 ping 连接。这个很棒的答案包含所有细节:

SQLAlchemy error MySQL server has gone away

【讨论】:

    【解决方案2】:

    分配 session=DBSession 将获得两个不同的会话实例

    这根本不是真的。 session = DBSession 是局部变量赋值,在 Python 中不能覆盖局部变量赋值(可以覆盖实例成员赋值,但这无关)。

    另外需要注意的是,默认情况下,scoped_session 会产生一个线程本地范围的会话(即同一线程中的所有代码都具有相同的会话)。由于您在同一个线程中调用 first() 和 second(),因此它们是同一个会话。

    您可以做的一件事是使用常规(无范围)会话,只需手动管理您的会话范围并在这两个函数中创建一个新会话。或者,您可以查看有关如何define custom session scope 的文档。

    【讨论】:

    • 该死,赏金到期了,我忘了回到这里给你......真糟糕,SO没有重新给我积分,所以我可以打开另一个赏金并将它给你。
    【解决方案3】:

    您似乎没有获得单独的 Session 实例。如果第一个查询成功提交,那么您的 Session 可能会在该提交之后过期。

    尝试为您的会话设置 auto-expire 为 false:

    DBSession = scoped_session(sessionmaker(expire_on_commit=False, autocommit=False, autoflush=False,  bind=engine))
    

    然后再提交。

    【讨论】:

      猜你喜欢
      • 2019-09-17
      • 1970-01-01
      • 1970-01-01
      • 2019-11-05
      • 1970-01-01
      • 2017-05-28
      • 1970-01-01
      • 2011-05-29
      • 1970-01-01
      相关资源
      最近更新 更多