SQlALchemy session詳解

系列文章:html

  1. Python SQLAlchemy入門教程

概念

session用於建立程序和數據庫之間的會話,全部對象的載入和保存都需經過session對象 。python

經過sessionmaker調用建立一個工廠,並關聯Engine以確保每一個session均可以使用該Engine鏈接資源:git

from sqlalchemy.orm import sessionmaker

# 建立session
DbSession = sessionmaker(bind=engine)
session = DbSession()

操做

session的常見操做方法包括:github

  1. flush:預提交,提交到數據庫文件,還未寫入數據庫文件中
  2. commit:提交了一個事務,把內存的數據直接寫入數據庫
  3. rollback:回滾
  4. close:關閉

在事務處理時,需注意一下兩點:sql

  1. 在事務處理過程發生異常時,進行rollback操做,不然會在下次操做時報錯:
Can’t reconnect until invalid transaction is rolled back
  1. 通常狀況下,在一個事務處理完成以後要關閉session,以確保數據操做的準確性。

建議封裝上下文方法:數據庫

from contextlib import contextmanager

@contextmanager
def session_maker(session=session):
    try:
        yield session
        session.commit()
    except:
        session.rollback()
        raise
    finally:
        session.close()

調用:緩存

def update_user():
    with session_maker() as db_session:
        db_session.query(Users).filter_by(name='test2').update({'email': 'test2@qq.com'})

線程安全

session不是線程安全的,而且咱們通常session對象都是全局的,那麼在多線程狀況下,當多個線程共享一個session時,數據處理就會發生錯誤。安全

爲了保證線程安全,需使用scoped_session方法:session

db_session = scoped_session(sessionmaker(bind=engine))

內部原理

session對象包含了三個重要的部分:多線程

  1. 標識映射(Identity Map)
  2. 對象的狀態 / 狀態跟蹤
  3. 事務

標識映射

標識映射是與ORM關聯的集合,經過標識映射保證了數據庫操做的準確性。

具體的實現原理是:維護一個Python字典(IdentityMap),關聯這個Session對象到數據庫ID的映射,當應用程序想要獲取一個session對象時,若該對象不存在,標識映射會加載該對象並緩存,若該對象已存在,則直接獲取。這樣的好處是:

  1. 已經被請求過的session對象緩存下來,不須要鏈接加載屢次,形成額外的開銷;
  2. 避免了數據不一致

狀態跟蹤

一個Session對象從建立到銷燬,依次經歷四種狀態,分別是:

  1. Transient:剛new出來的對象,還不在會話中,也沒有保存到數據庫。
  2. Pending:transient的對象調用add後,就會變成pending狀態,這時會加入sqlalchemy的監管範圍,數據並未更新到數據庫。
  3. Persistent:該狀態代表數據庫裏已經記錄了該對象,在兩種狀況下對象處於該狀態:一是經過flush()方法刷新pending對象,二是從數據庫query()獲得對象。
  4. Detached:在會話中的事務提交以後,全部的對象都將是Detached狀態。

所謂的狀態跟蹤,就是跟蹤以上四個狀態,保證數據的準確性並在合理的時機丟棄對象以保證合理開銷,那麼具體是怎麼實現的呢?

咱們能夠看到,只有在pending狀態時,對象的內存數據和數據庫中的數據不一致,在Persistent狀態時,內存數據和數據庫數據已經一致,那麼此後任意時刻丟棄該對象數據都是能夠的,這時就須要找個合適的時機丟棄對象,過早或過晚都有其缺陷。因而,就讓垃圾回收器來作決定,在內存不夠的時候釋放對象,回收內存。

Session對象採用了弱引用機制,所謂弱引用,就是說,在保存了對象的引用的狀況下,對象仍然可能被垃圾回收器回收。在某一時刻經過引用訪問對象時,對象可能存在也可能不存在,若是對象不存在,就從新從數據庫中加載對象。而若是不但願對象被回收,只須要另外保存一個對象的強引用便可 。

session對象包括三個屬性:

  1. new:剛加入會話的對象
  2. dirty:剛被修改的對象
  3. deleted:在會話中被刪除的對象

三個屬性共同的特色就是內存的數據和數據庫數據不一致,也就是對象處於pending狀態,這也就代表了session保存了全部對象處於pending狀態的強引用。

以上。

代碼可參照:my github

相關文章
相關標籤/搜索