假设已有一个 Session 工厂类:html
lang:python Session = sessionmaker(bind=some_engine)
那么 session 实例的生命周期能够为:python
###最短模式 —— 每次请求新建一个 session,用完就 closeweb
lang:python @contextmanager def get_session_scope(): try: s = Session() yield s s.commit() except: s.rollback() finally: s.close()
这种模式不适合 web 项目或者说其缺点主要在于对 链接池(db pool) 的消耗过快。实际使用中发现,被 close 的 session 的 链接并无即时返回可用状态。所以在请求频繁时,会出现等待链接的状况。sql
###最长模式 —— 全程使用一个 sessionflask
lang:python session = Session()
这种方式更加不适合 web 项目。由于根据 SQLAlchemy 的文档描述:安全
The Session object is entirely designed to be used in a non-concurrent fashion, which in terms of multithreading means “only in one thread at a time”.
session 并非线程安全的。这种并发式的 session 使用会致使错误。session
###Thread-Local模式 —— 生命周期与 request 同步并发
lang:python @app.before_request def init_session(): g.session = Session() @app.tear_down_request def close_session(): g.session.close()
这其实才是最适合 web 项目的 session 管理方式。(伪代码中没有写 commit 和 rollback,可自行添加)这样即避免了链接池的过快消耗,又避免了并发问题。这也是 SQLAlchemy 文档中推荐的作法。app
实践上更靠谱的一段代码多是:线程
lang:python from sqlalchemy.orm import scoped_session, sessionmaker from flask import g Session = scoped_session(sessionmaker(bind=some_engine), scopefunc=g._get_current_object)
更更可靠的一种方法应该是使用官方扩展,如 Flask-SqlAlchemy