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

相关文章
相关标签/搜索