第十三章 Cache
Cache的数据结构
Cache的数据结构是这样的一个字典:
{
field: {
record_id: value
},
field: {
context_key:{
record_id: value
}
}
}
Cache在初始化时会初始化一个_data的默认字典的字典属性, 用来存储缓存. 然后定义了一系列的方法来读取或者存储缓存.
Cache对象对外公开的主要几个方法有:
- contains(record, field): 用来判断字段field在记录record中是否缓存
- get(record,field,default=NOTHING): 获取record记录的field字段的缓存值
- set(record,field,value): 设置record记录field字段的缓存值
- update(records,field,values): 更新记录集records的field字段的缓存值。
- remove(record,field): 删除记录record的字段field的缓存值
- get_values(records,field): get的复数方法
- get_until_miss(records,field): 获取记录集records中的field字段的缓存值,直到某个值没有找到
- get_records_different_from(records,field,value): 获取记录集中与给定的值不同的field字段的缓存值
- get_fields(record): 获取记录record中已缓存的字段列表,不包含id字段
- get_records(model,field): 获取模型model的字段field的缓存的记录集
- get_missing_ids(records,field): 获取记录集records中没有缓存字段field的值的ids
- invalidate(spec=None): 设置缓存无效,不传spec则清空所有缓存,否则清空指定的缓存。
- check(env): 检查指定的环境变量env的缓存数据的一致性。
存储字段和计算字段的读取逻辑
odoo为了读取的效率考虑,引入缓存的机制。我们知道odoo中的字段大概分为存储和非存储两类,在read方法中,对此做了区分,所有的存储字段和有依赖字段的计算字段的读取操作都将从数据库中读取并更新,而没有依赖的计算字段将直接从缓存中读取。
def read(self, fields=None, load='_classic_read'):
""" read([fields])
Reads the requested fields for the records in ``self``, low-level/RPC
method. In Python code, prefer :meth:`~.browse`.
:param fields: list of field names to return (default is all fields)
:return: a list of dictionaries mapping field names to their values,
with one dictionary per record
:raise AccessError: if user has no read rights on some of the given
records
"""
fields = self.check_field_access_rights('read', fields)
# fetch stored fields from the database to the cache
stored_fields = set()
for name in fields:
field = self._fields.get(name)
if not field:
raise ValueError("Invalid field %r on model %r" % (name, self._name))
if field.store:
stored_fields.add(name)
elif field.compute:
# optimization: prefetch direct field dependencies
for dotname in self.pool.field_depends[field]:
f = self._fields[dotname.split('.')[0]]
if f.prefetch and (not f.groups or self.user_has_groups(f.groups)):
stored_fields.add(f.name)
self._read(stored_fields)
return self._read_format(fnames=fields, load=load)
_read方法用来读取存储字段,_read_format方法用来从缓存中读取字段的值。字段本身的读取逻辑也有涉及到缓存的部分,请参考字段一章。
事务
事务(Transcation)是odoo15.0新引入的中间组件对象, 用来管理ORM的数据结构和事务.
事务主要有如下几个重要的属性:
- registry: 注册中心对象, 用来管理数据库中模型注册的工具。
- envs: 环境变量集合,集合使用了WeakSet数据类型。
- cache: 缓存对象实例
- protected: StackMap对象实例
- tocompute: 挂起的计算操作,默认字典类型(set)。
- towrite: 挂起的更新操作
然后有如下几个方法
flush
def flush(self):
""" Flush pending computations and updates in the transaction. """
env_to_flush = None
for env in self.envs:
if isinstance(env.uid, int) or env.uid is None:
env_to_flush = env
if env.uid is not None:
break
if env_to_flush is not None:
env_to_flush['base'].flush()
flush方法的作用是将挂起的计算生效并更新到事务中.
clear
def clear(self):
""" Clear the caches and pending computations and updates in the translations. """
self.cache.invalidate()
self.tocompute.clear()
self.towrite.clear()
clear方法主要作用是设置缓存无效, 并清空要重新计算和重写的逻辑.
reset
def reset(self):
""" Reset the transaction. This clears the transaction, and reassigns
the registry on all its environments. This operation is strongly
recommended after reloading the registry.
"""
self.registry = Registry(self.registry.db_name)
for env in self.envs:
env.registry = self.registry
lazy_property.reset_all(env)
self.clear()
reset方法的作用是重置事务, 具体地说, 就是重新实例化注册中心, 并将环境变量中的注册中心重新加载. 最后调用clear方法 清空缓存和计算逻辑.