本文主要用來探討如何合理的使用 sqlalchemy 的 session的一些基礎知識
session 可能遇到的問題
- 占用連接未釋放,導致數(shù)據(jù)庫連接滿
- 已查詢的數(shù)據(jù)使用時返回
None - 已變更過數(shù)據(jù),但是查詢時并沒有得到最新的更新
session 是什么
它管理與數(shù)據(jù)庫相關的所有操作,包括數(shù)據(jù)連接、釋放、事物相關等操作。
它作為程序訪問數(shù)據(jù)庫的一個
entrypoint它把從數(shù)據(jù)中取回的數(shù)據(jù)映射為
ORM中的一個對象,并且存儲在一個名為Identity Map的數(shù)據(jù)結構中它在存入數(shù)據(jù)時把一個ORM對應到一個數(shù)據(jù)表
session生命周期管理
使用session的一個基本準則,一個應用應該去管理session的生命周期,對于處理特殊數(shù)據(jù)的函數(shù)session應該作為一個參數(shù)被傳遞進來并且使用。
- 對于一個后臺任務,建議每個子線程分配一個session,生命周期為子線程生命周期
- 對于命令行任務,建議應用建立一個單獨的全局session
- GUI驅動的應用,建議一個用戶事件作為session的生命周期
- 對于WEB應用,建議一個request作為生命周期
創(chuàng)建session
- 對于
sessionmaker一般是作為一個全局變量僅定義一次 - 對于
session一般是在有數(shù)據(jù)邏輯操作開始的時候創(chuàng)建
使用session
在session中存儲了一個對象的弱引用
- 每條數(shù)據(jù)只保留一個副本,使用主鍵識別一條數(shù)據(jù)。如果查詢時該數(shù)據(jù)已經(jīng)存在session中,查詢后將不會替換該數(shù)據(jù),除非該數(shù)據(jù)已過期。
- 查一條數(shù)據(jù)的最新狀態(tài)時先commit再query
- session的細節(jié),事物和異常管理盡量與程序的細節(jié)分開處理
commit&&close
- 在
commit或者rollback前每個session代表一個事物, 在commit后session中的數(shù)據(jù)會被標記為過期,但是不會被刪除。應保證每個事物盡量短,避免持有數(shù)據(jù)鎖時間過長影響數(shù)據(jù)庫并發(fā)量。 - 關閉
session后所有的資源都會被釋放,前面說了session中的ORM都是弱引用,查詢所得的數(shù)據(jù)都可能消失。 - 保證任務結束后關閉
session防止資源泄漏,畢竟一個應用一般也就分配幾百個連接,使用完后就么有了。
session使用例子
from contextlib import contextmanager
@contextmanager
def session_scope():
"""Provide a transactional scope around a series of operations."""
session = Session()
try:
yield session
session.commit()
except:
session.rollback()
raise
finally:
session.close()
def run_my_program():
with session_scope() as session:
ThingOne().go(session)
ThingTwo().go(session)