SQLAlchemy 对象缓存和刷新
SQLAlchemy 带有对象缓存机制,在重复查询相同的对象时,直接先查询本地的缓存,而不需要从数据库加载数据。
在每个 model 对象的内部,SQLAlchemy 在对象的 __dict__
中维护对象的状态。它往 __dict__
中加入对象的状态 _sa_instance_state
,通过这个值来跟踪对象。_sa_instance_state
是 sqlalchemy.orm.state.InstanceState
类型,里面保存这个对象的 session 、orm mapper 等等信息。
在一般的情况下,这种方法会非常高效。但如果在进行跨进程操作时,如果不加以特别的处理,对象缓存机制会导致一个进程无法取得另外一个进程的对象更新情况。
假设两个进程 A,B,A 在操作 object 的更新,B 等待 object 的状态,如下:
A 进程
object = session.query(MyObject).first()# do somethingwith session.begin(): object.status = 'SUCCESS'
B 进程
while True: object = session.query(MyObject).first() if object.status == 'SUCCESS': # do something break sleep(10)
在 B 进程中,虽然每次循环都进行查询,但由于缓存机制,其实只有第一次会从数据库加载,在数据过期前,都是直接读取缓存,所以 B 进程会一直在等待状态。
解决的方法是进行对象刷新。对于这些需要每次更新状态的对象,通过 session.refresh(object)
或 session.expire(object)
,让对象过期,从而在下次访问时重新加载。
B 进程
object = session.query(MyObject).first()while True: if object.status == 'SUCCESS': # do something break session.refresh(object) sleep(10)
session.refresh
或 session.expire
支持只刷新特定的属性,如
session.refresh(object, ['status'])
这种做法就降低重新加载时所传递的数据量,具有 BLOB 大数据量的字段可又不重新加载。