Python SQLAlchemy会话重新连接

Python SQLAlchemy会话重新连接,python,sqlalchemy,Python,Sqlalchemy,如果查询返回一个操作性错误,比如用户无权访问数据库或类似的东西,我如何强制我的引擎重新连接 engine = create_engine(url, pool_recycle=3600) Session = sessionmaker(bind=engine) try: sesh = Session() sesh.query.... sesh.close() except OperationalError: # force engine to rec

如果查询返回一个操作性错误,比如用户无权访问数据库或类似的东西,我如何强制我的引擎重新连接

engine = create_engine(url, pool_recycle=3600)
Session = sessionmaker(bind=engine)

try:
      sesh = Session()
      sesh.query....
      sesh.close()
except OperationalError:
      # force engine to reconnect here somehow?

如果捕获到一个错误,表明在操作过程中连接已关闭,SQLAlchemy将在下次访问时自动重新连接。但是,当数据库断开连接时,事务将消失,因此SQLAlchemy要求您在会话上发出rollback(),以便在应用程序中确定将发生新事务。然后,您需要重新开始整个交易


处理这个问题有几个角度。您应该通读文档中说明了使用断开连接的两种方法的部分。除此之外,如果您真的想从中断的地方恢复您的事务,那么您需要“重放”整个事务,假设您在事务中做了不止一件事。这最适合应用程序代码,该应用程序代码将需要执行的操作打包到可以再次调用的函数中。请注意,SQLAlchemy的未来版本可能会引入一个名为事务重放扩展的扩展,该扩展提供了另一种方法,但是它会有很多警告,因为以通用方式重放丢失的事务不是一件小事

自从这个问题第一次被回答以来,已经发生了很多事情

通过采取一种悲观的错误处理方法,您可以获得最大的bug效果-实现简单且非常有效

创建引擎时应用
pool\u pre\u ping=True
,如下所示:

engine = create_engine("mysql+pymysql://user:pw@host/db", pool_pre_ping=True)
请参阅更多:


另一种方法是在错误发生时以一种乐观的方式处理错误。在这种情况下,您可以将execute语句包装在try and except中,并在引发异常时使连接无效。一旦连接失效,您就可以重新实例化它

请参阅更多:



这两种方法都适用于您的连接可能会超时的情况,例如过夜/周末。它还使It操作更容易关闭数据库,并且不必太担心依赖于重启的下游应用程序。无论如何,这不是一个灵丹妙药,如果您处理非常关键的事务,那么就值得考虑安全事务处理(正如zzzeek所提到的)

如果您在烧瓶中使用sqlalchemy,当您查询

MyModel.query.all()
你会得到这样的错误

  File "./lib/python2.7/site-packages/sqlalchemy/engine/base.py", line 427, in _revalidate_connection
    "Can't reconnect until invalid "
StatementError: (sqlalchemy.exc.InvalidRequestError) Can't reconnect until invalid transaction is rolled back
您只需通过以下方式重新连接DB

MyModel.query.session.close()
MyModel.query.all()

包含一些改进。TL;DR:在sqlalchemy 1.2中,您可以执行
engine=create\u engine(“mysql://user:pw@主机/db”,pool\u pre\u ping=True)
。它检查连接是否仍处于活动状态,如果没有,则重新连接。它的开销很小(它发送一个
SELECT 1
)。这也可以通过配置选项设置:SQLALCHEMY\u ENGINE\u options={“pool\u pre\u ping”:True,“pool\u recycle”:300,}我在使用相同会话对象的长时间运行的进程中遇到了相同的问题
pool\u pre\u ping
有效,但我必须在查询后添加
session.close()
,因为pool\u pre\u ping仅在获取新连接时发生的
checkout
事件中有效。