按照我们在How to close sqlalchemy connection in MySQL中评论的内容,我正在检查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()
不足够吗?答案 0 :(得分:62)
这里有一个关于“会话”这个词的中心混淆。我不确定这里,但看起来你可能会混淆SQLAlchemy Session和MySQL @@session,它指的是你第一次建立MySQL连接和断开连接时的范围。
这两个概念不一样。在特定的数据库连接上,SQLAlchemy会话通常表示一个或多个事务的范围。
因此,按字面意思询问您的问题的答案是调用session.close()
,即“如何正确关闭SQLAlchemy会话”。
但是,你的问题的其余部分表明你想要一些功能,当特定的Session
关闭时,你也希望关闭实际的DBAPI连接。
这基本上意味着您希望禁用connection pooling。正如其他答案所提到的那样,很简单,use NullPool。
答案 1 :(得分:40)
session.close()
会将连接返回到Engine的连接池,并且不会关闭连接。
engine.dispose()
将关闭连接池的所有连接。
如果设置poolclass=NullPool
,引擎将不会使用连接池。因此,连接(SQLAlchemy会话)将在session.close()
之后直接关闭。
答案 2 :(得分:0)
在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("**********************")