如何关闭 SQLAlchemy 会话?

104

根据我们在如何在MySQL中关闭SQLAlchemy连接中的评论,我正在检查SQLAlchemy创建的数据库连接,但我无法在不退出Python的情况下关闭它们。

如果我在python控制台中运行此代码,则会一直保持会话开启状态,直到我退出Python:

from sqlalchemy.orm import sessionmaker
from models import OneTable, get_engine

engine = get_engine(database="mydb")
session = sessionmaker(bind=engine)()

results = session.query(OneTable.company_name).all()

# some work with the data #

session.close()

我找到的唯一解决方法是在结尾处调用engine.dispose()来关闭它。

根据我提供的链接中的评论,我的问题现在是:

  • engine.dispose()为什么是关闭会话的必要步骤?
  • session.close()不够吗?

1
使用 sqlalchemy.pool.NullPool 仍无法解决您的问题吗? - Alvaro Fuentes
我希望这两个链接能够帮到你:http://docs.sqlalchemy.org/en/rel_0_8/glossary.html?highlight=release 和 http://docs.sqlalchemy.org/en/rel_0_8/core/pooling.html?highlight=pooling#switching-pool-implementations。 - Alvaro Fuentes
3个回答

126
这里有一个关于“会话”单词的中心混淆。 我不确定,但似乎您可能会将SQLAlchemy SessionMySQL @@session混淆,后者指的是当您首次连接到MySQL以及断开连接时的范围。
这两个概念不同。 SQLAlchemy会话通常代表特定数据库连接上的一个或多个事务的范围
因此,根据字面意思提问的答案是调用session.close(),也就是“如何正确关闭SQLAlchemy会话”。
然而,您问题的其余部分表明您希望当特定Session关闭时,实际的DBAPI连接也关闭。
这基本上意味着您希望禁用连接池。 正如其他答案所提到的那样,很容易使用NullPool来实现。

10
完全懂了,你指出来后我注意到我混淆了SQLAlchemy和MySQL会话。现在使用get_engine(database="mydb", poolclass=NullPool)后,当我session.close()时就可以将其关闭。非常感谢! - fedorqui
我猜我遇到了一个由于会话未正确关闭而引起的问题。我的API给我随机数量的行。例如,我的表(mysql)中有10行。当我访问我的API时,我会得到10、0、9等结果。附注:我使用的是SQLAlchemy(而不是Flask SQLAlchemy)。请指导我。 - Hussain

112

session.close() 将会将连接返回给Engine的连接池,而不会关闭连接。

engine.dispose() 将会关闭连接池中所有的连接。

如果你设置 poolclass=NullPool,Engine将不会使用连接池。所以,在 session.close() 后,连接(SQLAlchemy session)将会直接关闭。


8
.dispose 会等待所有待处理的提交吗? - matanster
7
根据文档,连接池中被检出的连接在引擎被释放或垃圾回收时不会被丢弃。 因此,任何未关闭的会话将被 engine.dispose() 忽略。 - Jamie Scott

-4
LogicBank中,我进行了一系列的单元测试。每个测试运行前都会复制一个SQLite数据库,代码如下:
copyfile(src=nw_source, dst=nw_loc)

每个测试都单独运行,但在“discover”模式下失败。很明显,某种方式复制数据库没有发生。
似乎单元测试可能没有按顺序运行。事实上,单元测试确实是串行运行的,所以那不是问题(记录下来,或许可以节省别人一些时间)。
经过相当多的折腾,出现了这种情况,因为之前的测试没有完全关闭数据库。不知怎么的,这干扰了上面的复制。我不需要去想原因...
由于以上的帖子,我像这样解决了它:
def tearDown(file: str, started_at: str, engine: sqlalchemy.engine.base.Engine, session: sqlalchemy.orm.session.Session):
"""
close session & engine, banner

:param file: caller, usually __file__
:param started_at: eg, str(datetime.now())
:param engine: eg, nw.logic import session, engine
:param session: from nw.logic import session, engine
:return:
"""

session.close()
engine.dispose(). # NOTE: close required before dispose!

print("\n")
print("**********************")
print("** Test complete, SQLAlchemy session/engine closed for: " + file)
print("** Started: " + started_at + " Ended: " + str(datetime.now()))
print("**********************")

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接