如何在sqlalchemy中正确关闭mysql连接?

时间:2018-01-11 17:44:43

标签: python mysql flask sqlalchemy

我想知道关闭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:disposeclose来电受到How to close sqlalchemy connection in MySQL的启发。顺便问一下,什么是'签出'连接?

2 个答案:

答案 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