我想知道关闭sqlalchemy
中所有mysql连接的正确方式是什么。
对于上下文,它是Flask应用程序,并且所有视图共享相同的session
对象。
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
已关闭且engine
已被处理
session.close()
engine.dispose()
但是根据数据库日志,我仍然有很多错误,例如[Warning] Aborted connection 940 to db: 'master' user: 'root' host: '172.19.0.7' (Got an error reading communication packets)
。
我尝试了一些解决方案,包括致电gc.collect()
和engine.pool.dispose()
,但没有成功......
我怀疑场景后引擎仍然打开了一些连接,需要关闭它们。无论如何列出引擎打开的所有会话/连接?
花了很多时间在这上面,任何建议/帮助/指针将非常感谢!感谢。
P.S:dispose
和close
来电受到How to close sqlalchemy connection in MySQL的启发。顺便问一下,什么是'签出'连接?
答案 0 :(得分:6)
这可能无法完全回答您的问题,但我一直在使用此方法来确保我的所有会话都已关闭。每个使用会话的函数都会获得provide_session装饰器。请注意,必须存在session=None
参数。
e.g
@provide_session()
def my_func(session=None):
do some stuff
session.commit()
我看到它在Incubator-Airflow项目中使用并且非常喜欢它。
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
答案 1 :(得分:1)
最后我找到了罪魁祸首:在后台进程中启动的apscheduler使用连接到数据库的session
,似乎没有正确释放它。
我们在Flask应用中处理sqlalchemy会话时发现的最佳做法是使用scoped_session
,并确保在请求结束时在其上调用remove()
(即appcontext_teardown
)。这也用于flask-sqlalchemy extension。