PHP中是否可实现类似Guava LoadingCache的带过期时间的加载式内存缓存?
PHP中是否可实现类似Guava LoadingCache的带过期时间的加载式内存缓存?
当然可以!我之前做Web项目时也碰到过一模一样的需求——不想每次都绕数据库取重复内容,就想要个像Guava LoadingCache那样,能自动过期、过期后自动从数据源刷新的缓存,省得自己写一堆重复的判断逻辑。
下面给你捋几种可行的方案,从手动实现到现成工具都有:
一、手动封装轻量版(无依赖,单请求内有效)
如果你的需求是同一次请求里避免重复查数据库,那用PHP的静态变量就能快速实现,完全不用装任何额外东西:
class SimpleLoadingCache { private static array $cache = []; /** * 获取缓存,不存在或过期时自动调用加载函数 * @param string $key 缓存键 * @param callable $loader 加载数据的回调(比如从数据库查询的逻辑) * @param int $ttl 过期时间,单位秒 * @return mixed */ public static function get(string $key, callable $loader, int $ttl = 300) { // 检查缓存是否存在且未过期 if (isset(self::$cache[$key]) && self::$cache[$key]['expires_at'] > time()) { return self::$cache[$key]['value']; } // 缓存失效,调用加载函数获取新数据 $value = $loader(); // 存入缓存,记录过期时间 self::$cache[$key] = [ 'value' => $value, 'expires_at' => time() + $ttl ]; return $value; } }
用的时候也很简单,比如从数据库取用户列表:
$users = SimpleLoadingCache::get('user_list', function() { // 这里写你的数据库查询逻辑 $pdo = new PDO('mysql:host=localhost;dbname=test', 'user', 'pass'); $stmt = $pdo->query('SELECT * FROM users'); return $stmt->fetchAll(PDO::FETCH_ASSOC); }, 3600); // 1小时过期
不过要注意:这种静态变量的缓存只在当前请求周期内有效,请求结束后PHP进程释放,缓存就清空了。如果要跨请求共享缓存,得用下面的方案。
二、跨请求的内存缓存(用APCu扩展)
如果想让缓存在不同请求之间也能复用,推荐用APCu——这是PHP官方维护的用户态内存缓存扩展,数据存在内存里,速度超快,完全符合你要的“memory cache”需求。
首先得确保你装了APCu扩展(大部分服务器都默认装了,没装的话用pecl install apcu就能搞定),然后封装一个类似LoadingCache的逻辑:
class ApcuLoadingCache { /** * 获取缓存,自动加载刷新 * @param string $key 缓存键 * @param callable $loader 数据加载回调 * @param int $ttl 过期时间,单位秒 * @return mixed */ public static function get(string $key, callable $loader, int $ttl = 300) { // 尝试从APCu取缓存 $value = apcu_fetch($key, $success); if ($success) { return $value; } // 缓存不存在或过期,加载新数据 $value = $loader(); // 存入APCu并设置过期时间 apcu_store($key, $value, $ttl); return $value; } }
用法和之前的手动版几乎一样,而且这个缓存是跨请求的,只要服务器不重启、缓存没过期,下次请求直接用就行,完全不用碰数据库。
三、框架自带的缓存方案(如果用PHP框架的话)
要是你用Laravel、Symfony这类主流框架,那根本不用自己封装,框架早就给你做好类似的功能了:
- 比如Laravel里的
Cache::remember方法,完美对应你的需求:
这里$users = Cache::remember('user_list', 3600, function() { return DB::table('users')->get(); });3600是过期时间(秒),回调里写数据库查询逻辑,缓存过期会自动调用回调刷新。 - Symfony的Cache组件也有类似的
get方法,用ArrayAdapter(内存)或RedisAdapter都能实现带TTL的自动加载。
总的来说,不管是自己手动写轻量版,还是用现成的扩展、框架工具,都能实现和Guava LoadingCache几乎一样的效果,完全能满足你“缓存x秒后自动从数据库刷新”的需求,比直接依赖数据库缓存高效多了。
内容来源于stack exchange
相关产品推荐
相关产品推荐

