Python 如何在sqlalchemy中正确关闭mysql连接?
我想知道在Python 如何在sqlalchemy中正确关闭mysql连接?,python,mysql,flask,sqlalchemy,Python,Mysql,Flask,Sqlalchemy,我想知道在sqlalchemy中关闭所有mysql连接的正确方法是什么。 对于上下文,它是一个Flask应用程序,所有视图共享相同的会话对象 engine = create_engine("mysql+pymysql://root:root@127.0.0.1/my_database") make_session = sessionmaker(bind=engine, autocommit=False) session = ScopedSession(make_session)() 当应用
sqlalchemy
中关闭所有mysql连接的正确方法是什么。
对于上下文,它是一个Flask应用程序,所有视图共享相同的会话
对象
engine = create_engine("mysql+pymysql://root:root@127.0.0.1/my_database")
make_session = sessionmaker(bind=engine, autocommit=False)
session = ScopedSession(make_session)()
当应用程序被撕下时,会话
关闭,引擎
被释放
session.close()
engine.dispose()
但是根据数据库日志,我仍然有很多错误,比如[Warning]中止了940到db的连接:'master'用户:'root'主机:'172.19.0.7'(读取通信数据包时出错)
我尝试了一些解决方案,包括调用gc.collect()
和engine.pool.dispose()
,但没有成功
我怀疑在幕后仍有一些连接被引擎打开,需要关闭。是否仍要列出引擎打开的所有会话/连接
在花了很多时间之后,任何建议/帮助/指针都将不胜感激!谢谢
注意:
dispose
和close
调用的灵感来自于。顺便说一句,“签出”连接是什么?这可能无法完全回答您的问题,但我一直在使用此方法来确保我的所有会话都已关闭。每个使用会话的函数都会获得提供会话装饰器。注意,session=None
参数必须存在
e、 g
我看到它在孵化器气流项目中使用,我非常喜欢它
import contextlib
from functools import wraps
...
Session = ScopedSession(make_session)
@contextlib.contextmanager
def create_session():
"""
Contextmanager that will create and teardown a session.
"""
session = Session()
try:
yield session
session.expunge_all()
session.commit()
except:
session.rollback()
raise
finally:
session.close()
def provide_session(func):
"""
Function decorator that provides a session if it isn't provided.
If you want to reuse a session or run the function as part of a
database transaction, you pass it to the function, if not this wrapper
will create one and close it for you.
"""
@wraps(func)
def wrapper(*args, **kwargs):
arg_session = 'session'
func_params = func.__code__.co_varnames
session_in_args = arg_session in func_params and \
func_params.index(arg_session) < len(args)
session_in_kwargs = arg_session in kwargs
if session_in_kwargs or session_in_args:
return func(*args, **kwargs)
else:
with create_session() as session:
kwargs[arg_session] = session
return func(*args, **kwargs)
return wrapper
导入上下文库
从functools导入包装
...
会话=范围会话(生成会话)
@contextlib.contextmanager
def create_会话():
"""
将创建和拆除会话的Contextmanager。
"""
会话=会话()
尝试:
收益期
session.expunge_all()
session.commit()
除:
会话。回滚()
提升
最后:
session.close()
def提供_会话(func):
"""
如果未提供会话,则提供会话的函数装饰器。
如果要重用会话或作为会话的一部分运行函数
数据库事务,则将其传递给函数(如果不是此包装器)
将创建一个并为您关闭它。
"""
@包装(func)
def包装(*args,**kwargs):
arg_session='session'
func_params=func.\u代码\u.co\u变量名
session_in_args=arg_session in func_参数和\
函数参数索引(参数会话)
最后我找到了罪魁祸首:在后台进程中启动的使用连接到数据库的会话,并且似乎没有正确释放它
此外,我们发现在Flask应用程序中处理sqlalchemy会话的最佳实践是使用作用域_会话
,并确保在请求结束时对其调用remove()
(即appcontext\u teardown
)。这也用于。签出连接是正在进行的会话等仍在使用的连接,dispose无法处理这些连接。总之,这个问题将受益于一个恰当的回答。@IljaEverilä谢谢!我努力创建了一个小例子来说明这个问题,但没有成功。。。奇怪的是,在一个小示例中,一切都很好,问题只出现在我们的大型代码库中。我怀疑我们在创建和结束会话方面做错了什么,最终导致了这种副作用。在这篇文章中,我实际上在寻找有关sqlalchemy会话的最佳实践(和问题)。您可以使用AssertionPool
调试签出的连接相关问题。@georgexsh谢谢,我正在使用此池进行调试!谢谢你的装饰!我们的大多数方法已经有了session
参数,因此我们可以稍后通过注入假会话或禁用提交来测试它,以确保数据在测试中没有被修改。(我们无法在每次测试时重新创建数据库,因为我们直接使用mysql进行测试,而且创建复杂数据库的成本相当高)这正是我一直在寻找的让我的数据库在Python Anywhere处于控制之下的方法!但是,我不得不删除**provide\u session**
decorator结尾的括号,以使其在我的代码中工作。谢谢你把你的答案放在这里@Sebastian-这至少对我是一个很大的帮助。不客气!你能分享更多关于你是如何发现的吗?@georgexsh我曾尝试使用AssertionPool
进行调试,但没有发现任何可疑之处。。。然后不知何故,我记得在某个时候,有一个过程从主过程分叉,然后罪犯被发现:)。
import contextlib
from functools import wraps
...
Session = ScopedSession(make_session)
@contextlib.contextmanager
def create_session():
"""
Contextmanager that will create and teardown a session.
"""
session = Session()
try:
yield session
session.expunge_all()
session.commit()
except:
session.rollback()
raise
finally:
session.close()
def provide_session(func):
"""
Function decorator that provides a session if it isn't provided.
If you want to reuse a session or run the function as part of a
database transaction, you pass it to the function, if not this wrapper
will create one and close it for you.
"""
@wraps(func)
def wrapper(*args, **kwargs):
arg_session = 'session'
func_params = func.__code__.co_varnames
session_in_args = arg_session in func_params and \
func_params.index(arg_session) < len(args)
session_in_kwargs = arg_session in kwargs
if session_in_kwargs or session_in_args:
return func(*args, **kwargs)
else:
with create_session() as session:
kwargs[arg_session] = session
return func(*args, **kwargs)
return wrapper