缓存架构设计

核心原则:读多写少的数据,缓存起来,减少数据库访问,提升性能

实体缓存

实体缓存就是整表缓存那些读取很多修改极少的数据,用于系统参数表、栏目分类表等。
实体类内使用'Meta.Cache.Entities'即可触发使用实体缓存,内部将执行一次查询('Select * From Table')加载整表数据为实体列表。
Meta.Cache.Entities就是这个实体列表,使用缓存实际上就是在这个列表上执行Find/FindAll操作。
基于性能考虑,建议单表数据小于1000行时使用,大于10000时坚决不要使用。

工具生成的实体业务类代码经常可以看到如下代码:

public Student FindByID(Int32 id)
{
    if (id <= 0) return null;

    if (Meta.Count >= 1000)
        return Find(__.ID, id);
    else // 实体缓存
        return Meta.Cache.Entities.Find(__.ID, id);
}

因此,FindByID在该表数据小于1000时,其实是使用实体缓存。

缓存默认过期时间60秒,过期后使用仍然是马上返回旧数据,同时开启异步查询更新缓存。
任何添删改等改动数据库的操作,都将会让缓存马上过期,并启动异步更新。
任何添删改操作,都将实时修改缓存,即使在异步更新完成之前,从缓存拿到的也是最新数据。除非有其它进程更新了数据表,此时需要等缓存的异步更新操作完成才能得到最新数据。

缓存更新策略

在没有使用事务时,对数据表的任何添删改,将会让该表的实体缓存马上过期,以及清空单对象缓存。
使用事务时,每一个添删改操作仅修改缓存,直到事务提交或回滚才清空缓存。

特别优化

SQLite没有索引表供快速查询表行数,而直接Select Count又慢,因此框架针对SQLite进行特别优化。
获取表行数时,如果有自增字段,首先获取其最大值临时充当表行数,然后启动异步查询Select Count以获取精确的表行数。
因此,SQLite使用Meta.Count时,第一次得到的数据可能有偏差,一会后即可得到精确数据。时间的长度主要由数据表大小决定,一百万数据大概需要几百毫秒。该偏差完全可以通过系统启动时进行系统预热来对冲掉。