我们在写SQLAlchemy的时候, 通常定义好 数据库表的类, 然后比如插入数据, 就会先生成一个对象, 然后做插入操作, 或者是query得到一个对象, 即查询结果.
在 session 中, 一个对象会有4个状态
- Transient: 此时对象并不在session中, 而且没有保存到数据库中, 比如刚新建的对象.
- Pending: 在调用add()时, 传入一个Transient状态的对象, 那个对象的状态改为Pending.
- Persistent: 一个对象存在于session, 且和数据库中的某一行对应.(比如query得到的结果)
- Detached: 对象和数据库中的一条数据对应, 但不在任何session中. 在commit之后, 所有的对象状态都变成Detached.
还有个 deleted, 是version1.1新增的状态.
一个对象从进入session 到 离开session, 通常要经过这4个过程.
from sqlalchemy import inspect
one = User("a", "b")
insp = inspect(one)
insp.transient
# Out[10]: True
insp.pending
# Out[11]: False
db.session.add(one)
insp.pending
# Out[13]: True
insp.transient
# Out[14]: False
db.session.commit()
insp.persistent
# Out[19]: True
session 会重点跟踪Pending状态的对象, 对于persistent的对象, 因为它表示对象和数据库中的数据已经一致, 那么这个对象随时可以从 session 去丢弃. 那么问题是 何时丢弃?
丢的太早, 用户如果刚好要查询刚刚插入的数据, 那么又得从数据库中读取一次; 如果丢的太晚, 大量对象会囤积在内存中. 于是这件事情就交给了 垃圾回收.
session 中的对象都有一个weakref(弱引用), 会被垃圾回收强制回收.
为了保证padding状态的数据不被强制回收, 用强引用保存它们, 在session的new, dirty, deleted属性中可以看到."new表示刚刚被加入会话的对象,dirty属性表示刚刚被修改的对象,而deleted属性表示在会话中被删除的对象"
one = User("a","b")
db.session.add(one)
print(db.session.new)
# Out[27]: IdentitySet([User: a])