缓存使用方法

基本操作

获取缓存 get()

php
use Viswoole\Cache\Facade\Cache;

// 获取缓存值
$value = Cache::get('key');

// 带默认值
$value = Cache::get('key', 'default');

// 获取不存在的键返回默认值
$name = Cache::get('user:name', '匿名用户');

设置缓存 set()

php
// 基本写入,使用驱动默认过期时间
Cache::set('key', 'value');

// 指定过期时间(秒)
Cache::set('key', 'value', 3600);      // 1小时后过期

// 使用 DateTime 对象指定过期时间
$expireAt = new DateTime('+1 hour');
Cache::set('key', 'value', $expireAt);

// NX 模式:仅当键不存在时写入(防覆盖)
Cache::set('lock:resource', 'locked', 300, true);

判断缓存存在 has()

php
if (Cache::has('user:session')) {
    // 会话缓存存在
}

删除缓存 delete()

php
// 删除单个缓存
Cache::delete('key');

// 批量删除
Cache::delete(['key1', 'key2', 'key3']);

清除所有缓存 clear()

php
// 清除当前驱动下的所有缓存
Cache::clear();

数值操作

自增 increment/inc()

php
// 设置初始计数器
Cache::set('views', 100);

// 自增(默认步长为 1)
Cache::inc('views');         // 101
Cache::inc('views', 10);     // 111

// 注意:值必须为数值类型,否则抛出异常

自减 decrement/dec()

php
// 自减
Cache::dec('stock', 1);      // 库存减 1

高级用法

获取并删除 pull()

php
// 获取缓存值并立即删除(原子操作)
$data = Cache::pull('temporary:data');

获取剩余有效期 ttl()

php
// 获取缓存剩余有效时间(秒)
$ttl = Cache::ttl('key');
if ($ttl === false) {
    // 缓存不存在或已过期
} elseif ($ttl === -1) {
    // 缓存长期有效(未设置过期时间)
} else {
    // 返回剩余秒数
}

竞争锁 lock()

php
try {
    // 获取锁
    $lockId = Cache::lock('order:create', 10, false, 5, 0.2);
    // 参数说明:
    // 场景标识, 过期时间(秒), 是否自动解锁, 重试次数, 重试间隔(秒)

    // 执行业务逻辑...
    createOrder();

    // 手动释放锁
    Cache::unlock($lockId);
} catch (\Viswoole\Cache\Exception\CacheErrorException $e) {
    // 获取锁失败
}

数组集合操作

php
// 向数组集合追加元素
Cache::sAddArray('tags', ['php', 'swoole']);
Cache::sAddArray('tags', 'redis');

// 获取数组集合所有元素
$tags = Cache::getArray('tags');
// 返回: ['php', 'swoole', 'redis']

// 从数组集合移除元素
Cache::sRemoveArray('tags', ['php']);

多缓存商店

php
// 切换到指定缓存商店
Cache::store('redis')->set('key', 'value', 3600);
$value = Cache::store('redis')->get('key');

// 添加自定义商店
Cache::addStore('custom', new MyCustomDriver());

// 判断商店是否存在
if (Cache::hasStore('custom')) {
    // 商店已注册
}

// 获取实际缓存标识(含前缀)
$realKey = Cache::getCacheKey('key');

序列化定制

php
// 自定义序列化方法(如使用 JSON 替代 PHP serialize)
Cache::setSerialize(
    fn($data) => json_encode($data),
    fn($data) => json_decode($data, true)
);

最佳实践

1. 缓存热点数据查询

php
public function getUser(int $id): array
{
    $cacheKey = "user:{$id}";

    // get() 不支持闭包回调,需手动判断 has() 后再 set()
    if (Cache::has($cacheKey)) {
        return Cache::get($cacheKey);
    }

    $user = User::find($id);
    $data = $user->toArray();
    Cache::set($cacheKey, $data, 3600);

    return $data;
}

注意get() 方法的第二个参数是默认值(mixed $default),不支持闭包回调。若传入闭包且缓存不存在,将直接返回闭包对象本身。如需实现"不存在时自动填充"的逻辑,请手动判断 has() 后再 set()

2. 缓存穿透防护

php
public function getData(string $key): mixed
{
    $cacheKey = "data:" . md5($key);

    if (Cache::has($cacheKey)) {
        return Cache::get($cacheKey);
    }

    $data = $this->fetchFromDatabase($key);

    // 即使数据为空也缓存短时间,防止穿透
    $ttl = empty($data) ? 60 : 3600;
    Cache::set($cacheKey, $data, $ttl);

    return $data;
}

3. 分布式锁控制并发

php
public function placeOrder(array $orderData): bool
{
    $lockId = Cache::lock("order:{$orderData['user_id']}", 5, true);

    try {
        // 检查是否重复下单
        if (Cache::has("pending:{$orderData['user_id']}")) {
            return false;
        }

        // 标记正在处理
        Cache::set("pending:{$orderData['user_id']}", true, 10);

        // 创建订单...
        return $this->createOrder($orderData);
    } finally {
        Cache::unlock($lockId);
    }
}