一级缓存全局设计

设计目的

方便的管理一级缓存,当有新的缓存需求出现时,尽可能的少改代码

框架背景

thinkphp6,需要借助模型事件特性

设计要点

  • 支持管理两种缓存场景,1、配置型小表整表缓存为单key 2、业务型大表分id缓存为多key
  • 缓存与模型绑定,通过模型自动拼接缓存key,如有新的缓存需求,配置下模型类和key就能够实现
  • 借助框架模型事件实现缓存的自动清除与刷新
  • 缓存时效加上一个随机数防雪崩
  • freshModelCache、destroyModelCache方法用于主动预热和刷新缓存
  • getDataFromCache、getDataFromCacheMulti是主要的对外提供服务的方法,用于读取数据,未命中缓存则读取数据库
  • 所有方法调用从模型类开始,所有模型类都继承了这些方法

具体实现

    /**
     * 获取模型缓存键名
     *
     * 根据模型类和ID生成对应的缓存键名,用于缓存管理
     *
     * @param mixed $id 数据主键
     * @return string 缓存键名
     */
    public static function getModelCacheKey($id)
    {
        $model_class = get_called_class();
        //以id为key管理缓存,具备一定数据量的业务表
        $map_id_key = [
            User::class => config('redis_schema.schema.user.info'),
            Staff::class => config('redis_schema.schema.user.staff'),
            Department::class => config('redis_schema.schema.user.department'),
            Company::class => config('redis_schema.schema.user.company'),
            Role::class => config('redis_schema.schema.user.role'),
        ];
        //缓存整表,用于配置型小表
        $map_all_table = [
            BaseLifecycleStatus::class => config('redis_schema.schema.system.base_lifecycle_status'),
        ];
        if(isset($map_id_key[$model_class])){
            if($id == 0){
                throw new CommonException('非法的ID');
            }
            return $map_id_key[$model_class].':'.$id;
        }
        if(isset($map_all_table[$model_class])){
            return $map_all_table[$model_class];
        }
        return '';
    }

    /**
     * 数据写入后的回调方法
     * 
     * 当数据写入完成后,根据模型名称删除相应的缓存信息,实现缓存更新机制。
     * 目前只处理User模型的缓存删除。
     * 
     * @param Model $data 写入的数据模型实例
     * @return void
     */
    public static function onAfterWrite($data)
    {
        $key = self::getModelCacheKey($data->id);
        if(!empty($key)){
            Cache::delete($key);
        }
    }

    /**
     * 数据删除后的回调方法
     *
     * 当数据被删除后,根据模型名称删除相应的缓存信息,实现缓存更新机制。
     *
     * @param Model $data 被删除的数据模型实例
     * @return void
     */
    public static function onAfterDelete($data)
    {
        $key = self::getModelCacheKey($data->id);
        if(!empty($key)){
            Cache::delete($key);
        }
    }


    /**
     * 获取数据,优先从缓存获取,缓存不存在则从数据库获取
     * 
     * @param mixed $id 数据主键
     * @return array|null
     */
    public static function getDataFromCache($id = 0): ?array
    {
        $key = self::getModelCacheKey($id);
        if(empty($key)){
            throw new CommonException('当前模型类未纳入缓存管理');
        }
        // 尝试从缓存获取数据
        $data = Cache::get($key);
        
        // 如果缓存中没有数据,则从数据库查询
        if (empty($data)) {
            if(empty($id)){
                $data = self::select();
            }else{
                $data = self::where('id', $id)->find();
            }

            if (!empty($data)) {
                $data = $data->toArray();
                // 将数据存入缓存,设置过期时间
                Cache::set($key, $data, getCacheTtl((new SettingRepository())->getSetting(['system_cache_ttl'])));
            }
        }
        
        return $data;
    }

    /**
     * 批量从缓存中获取数据
     * 
     * @param array $ids 需要获取数据的ID数组
     * @return array 以ID为键的数据数组
     */
    public static function getDataFromCacheMulti($ids){
        $res =  [];
        foreach ($ids as $id) {
            $res[$id] = self::getDataFromCache($id);
        }
        return $res;
    }

    /**
     * 刷新模型缓存
     * 
     * 从数据库重新加载数据并更新缓存,用于在数据变更后保持缓存与数据库的一致性
     * 
     * @throws CommonException 当前模型类未纳入缓存管理时抛出异常
     * @return void
     */
    public static function freshModelCache()
    {
        $key = self::getModelCacheKey(0);
        if(empty($key)){
            throw new CommonException('当前模型类未纳入缓存管理');
        }
        Cache::set($key, self::select()->toArray(), getCacheTtl((new SettingRepository())->getSetting(['system_cache_ttl'])));
    }
    
    /**
     * 删除模型缓存
     * 
     * 删除模型在缓存中的数据,用于在数据变更后清理缓存
     * 
     * @throws CommonException 当前模型类未纳入缓存管理时抛出异常
     * @return void
     */
    public static function destroyModelCache(){
        $key = self::getModelCacheKey(0);
        if(empty($key)){
            throw new CommonException('当前模型类未纳入缓存管理');
        }
        Cache::delete($key);
    }
posted @ 2025-09-03 11:25  gltttt  阅读(0)  评论(0)    收藏  举报