python - 未关闭的连接 SQLAlchemy

标签 python mysql sqlalchemy

我最近在我使用 SQLAlchemy 运行的守护进程的应用程序日志中看到 MySQL 服务器已经消失

我将每个数据库查询或更新包装在装饰器中,装饰器应在完成后关闭所有 session 。理论上,这也应该关闭连接

我的装饰器看起来像

  def dbop(meth):
    @wraps(meth)
    def nf(self, *args, **kwargs):
      self.session = self.sm()
      res = meth(self, *args, **kwargs)
      self.session.commit()
      self.session.close()
      return res
    return nf

我还在 Python 脚本的顶部初始化了数据库:

  def initdb(self):
    engine = create_engine(db_url)
    Base.metadata.create_all(engine)
    self.sm = sessionmaker(bind=engine,
                           autocommit=False,
                           autoflush=False,
                           expire_on_commit=False)

据我了解,我收到该错误是因为我的连接超时。如果我将每个方法包装在上面的装饰器中,为什么会出现这种情况?这是因为即使在连接关闭后 expire_on_commit 也会导致查询并可能重新打开它们吗?这是因为 Base.metadata.create_all 导致执行 SQL,从而打开一个未关闭的连接吗?

最佳答案

您的 session 绑定(bind)到“引擎”,而“引擎”又使用连接池。每次 SQLAlchemy 需要一个连接时,它都会从池中 check out 一个连接,如果完成,它会返回到池中,但它不会关闭!这是减少打开/关闭连接开销的常用策略。您在上面设置的所有选项只会影响 session ,不会影响连接!

默认情况下,池中的连接将无限期保持打开状态。

但 MySQL 会在一定数量的不活动后自动关闭连接(参见 wait_timeout)。

这里的问题是,如果您的 Python 进程处于不活动超时状态,MySQL 服务器将不会通知您连接已关闭。相反,下一次向该连接发送查询时,Python 将发现该连接不再可用。如果由于其他原因导致连接丢失,也会发生类似的事情,例如强制服务重启,不等待打开的连接完全关闭(例如,在 postgres 重启中使用“立即”选项)。

这是您遇到异常的时候。

SQLAlchemy 为您提供了各种处理此问题的策略,这些策略在@lukas-graf 提到的“Dealing with Disconnects”部分中有详细记录

如果您跳过一些障碍,您可以获得对 session 当前正在使用的连接的引用。您可以那样关闭它,但我强烈建议反对这样做。相反,请引用上面的“处理断开连接” session ,让 SQLAlchemy 透明地为您处理这个问题。在您的情况下,设置 pool_recycle option可能会解决您的问题。

关于python - 未关闭的连接 SQLAlchemy,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30036597/

相关文章:

python - Tkinter 小部件之间的空间不断增长

php - 无法从数据库获取数据

python - SQLAlchemy - 访问反射表的别名列时出现 NoReferencedTableError 异常

python - SQLAlchemy 在执行查询中缓存 now()

mysql - 从连接查询中获取不同的值(连接表)

python - SQLAlchemy:如何向现有表添加列?

python - 为什么python截断 float 为整数?

python - 为什么在转换为 exe 后出现 pyttsx3 错误?

python - Sphinx 和可重复使用的 Django 应用程序

php - 分组后从两个表中减去列(用于库存)