手上有个 ThinkPHP 5.1 的企业官网,前台每次打开页面都要查十几次数据库:站点信息、公司信息、导航菜单、产品分类、政策条款……全在 Common 基类的 initialize() 里,每个页面都跑一遍。

装了 Redis 之后,第一次访问缓存起来,后面的请求直接读 Redis,数据库查询降到接近零。

问题分析

前台的 Common.php 是所有控制器的基类,initialize() 里干了这些事:

protected function initialize(){
    $this->assign('site_info', $this->getSiteInfo());       // 查1次
    $this->assign('recommended_section', ...);               // 查1次
    $this->assign('company_info', $this->getCompanyInfo());  // 查1次
    $this->assign('recommended_category', ...);              // 查1次
    $this->assign('all_product_category', ...);              // 查1次
    $this->assign('inquiry_product', ...);                   // 读配置
    $this->assign('all_country', ...);                       // 读配置
    $this->assign('privacy_policy', $this->getPolicy(1));    // 查1次
    $this->assign('logistics_policy', $this->getPolicy(2));  // 查1次
    $this->assign('top', $this->getTopNav());                // 查1次
}

加上 get_system_val() 每次也查数据库,一个页面下来轻松 15+ 次数据库查询。这些数据其实很少变化,完全没必要每次都查。

方案选择

三个选择:文件缓存、Redis、Memcached。

选了 Redis,原因:

  • 速度最快,毫秒级响应
  • 支持数据结构,方便后续扩展
  • 宝塔面板一键安装,零配置
  • ThinkPHP 5.1 原生支持

安装步骤

宝塔面板操作:

  1. 软件商店 → 搜索 Redis → 安装
  2. 软件商店 → PHP 7.4 → 安装扩展 → redis
  3. 重启 PHP

验证:

redis-cli ping   # 返回 PONG
php -r "echo extension_loaded('redis') ? 'OK' : 'NO';"   # 返回 OK

ThinkPHP 配置

修改 config/cache.php

return [
    'type'       => 'redis',
    'host'       => '127.0.0.1',
    'port'       => 6379,
    'password'   => '',
    'select'     => 0,
    'timeout'    => 3,
    'expire'     => 3600,
    'prefix'     => 'xm_',
    'serialize'  => true,
];

给查询加缓存

改造模式很简单,每个方法开头加缓存读取,结尾加缓存写入:

public function getSiteInfo(){
    $cached = cache('site_info');
    if ($cached) return $cached;

    // 原来的数据库查询...
    $site_info = db('site')->where('id', 1)->find();
    // 处理数据...

    cache('site_info', $site_info, 3600); // 缓存1小时
    return $site_info;
}

一共改了 6 个方法:getSiteInfo、getCompanyInfo、getRecommendedSection、getProductsCategory、getTopNav、getPolicy。

get_system_val 也加缓存

这个函数被调用得最频繁,每次读一个系统配置值都要查数据库。用 static 变量做请求内缓存:

function get_system_val($code){
    static $cache = [];
    if (!isset($cache[$code])) {
        $cache[$code] = db('system_config')->where('code', $code)->value('val');
    }
    return $cache[$code];
}

后台修改时清缓存

数据被缓存了,后台修改数据后要及时清缓存,不然前台看到的还是旧数据:

// 系统设置保存后
\think\facade\Cache::clear();

后台菜单也缓存

后台的 left_nav() 函数每次请求查 3 次数据库生成菜单。菜单在登录后基本不变,缓存到 session 里:

function left_nav(){
    $cacheKey = 'left_nav_' . $user_id;
    $cached = session($cacheKey);
    if ($cached) {
        echo $cached;
        return;
    }
    // 生成菜单...
    session($cacheKey, $html);
    echo $html;
}

效果

  • 首次访问:查数据库,结果写入 Redis,耗时正常
  • 后续访问:直接读 Redis,数据库查询降到接近 0
  • 缓存过期:1 小时后自动刷新
  • 手动更新:后台修改数据时自动清缓存

对于这种内容不常变化的企业官网,Redis 缓存的性价比非常高。