假設已有一個 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