我有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
第一个()完成(大约需要4个小时),我看到"进入第二个功能"打印然后立即给我一个错误:
sqlalchemy.exc.OperationalError: (OperationalError) (2006, 'MySQL server has gone away')
从阅读文档我认为分配session = DBSession将获得两个不同的会话实例,因此第二个()不会超时。我也试过玩pool_recycle,这似乎没有任何效果。在现实世界中,我不能将first()和second()拆分为2个脚本:second()必须在first()之后立即执行()
答案 0 :(得分:2)
您的引擎(不是会话)会保留一个连接池。当一个mysql连接几个小时没有被使用时,mysql服务器会关闭套接字,这会导致一个" Mysql服务器已经消失了#34;尝试使用此连接时出错。如果你有一个简单的单线程脚本,那么用create_engine
调用pool_size=1
可能就可以了。如果没有,您可以在从池中签出连接时使用事件来ping连接。这个伟大的答案包含所有细节:
答案 1 :(得分:1)
您似乎没有获得单独的会话实例。如果第一个查询成功提交,那么您的会话可能会在提交后到期。
尝试将会话的自动过期设置为false:
DBSession = scoped_session(sessionmaker(expire_on_commit=False, autocommit=False, autoflush=False, bind=engine))
然后再提交。
答案 2 :(得分:1)
分配session = DBSession将获得两个不同的会话实例
这根本不是真的。 session = DBSession
是局部变量赋值,并且您不能在Python中覆盖局部变量赋值(您可以覆盖实例成员赋值,但这是无关的)。
另外需要注意的是,scoped_session默认情况下会产生一个线程局部范围的会话(即同一个线程中的所有代码都具有相同的会话)。由于您在同一个线程中调用first()和second(),因此它们是同一个会话。
您可以做的一件事是使用常规(无范围)会话,只需手动管理会话范围并在两个函数中创建新会话。或者,您可以查看有关如何define custom session scope的文档。