news 2026/6/1 11:22:00

PHP与Redis缓存实践完整方案

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
PHP与Redis缓存实践完整方案

PHP与Redis缓存实践完整方案

Redis在PHP项目里太常用了。缓存、队列、计数器、排行榜,各种场景都能用上。今天写一份完整的Redis实践指南。

先从最基础的连接和基本操作说起。

```php
// 连接Redis
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
// 如果有密码
// $redis->auth('password');
// 选择数据库
// $redis->select(1);

echo "连接状态: " . ($redis->ping() ? '正常' : '异常') . "\n";

// 字符串操作
$redis->set('key1', 'value1');
echo $redis->get('key1') . "\n";

// 带过期时间的设置
$redis->setex('session:123', 3600, 'user_data');
$redis->set('temp', '临时数据', 60); // 60秒过期

// 批量操作
$redis->mSet(['k1' => 'v1', 'k2' => 'v2', 'k3' => 'v3']);
$values = $redis->mGet(['k1', 'k2', 'k3']);
print_r($values);
?>
```

List可以用作队列或栈。

```php
// 列表操作
$redis->del('queue');

// 从左边推入
$redis->lPush('queue', '任务C');
$redis->lPush('queue', '任务B');
$redis->lPush('queue', '任务A');

// 从右边弹出(先进先出)
while ($task = $redis->rPop('queue')) {
echo "处理: $task\n";
}

// 队列长度
$redis->lPush('queue', 'task1', 'task2', 'task3');
echo "队列长度: " . $redis->lLen('queue') . "\n";

// 范围获取
$range = $redis->lRange('queue', 0, -1);
print_r($range);

// 阻塞弹出(等待队列有数据)
// $task = $redis->brPop(['queue'], 5); // 等待5秒
?>
```

Hash适合存储对象类型的数据。

```php
$redis->del('user:1001');

// 存储用户信息
$redis->hSet('user:1001', 'name', '张三');
$redis->hSet('user:1001', 'age', 28);
$redis->hSet('user:1001', 'email', 'zhangsan@test.com');

// 获取单个字段
echo "姓名: " . $redis->hGet('user:1001', 'name') . "\n";

// 获取所有字段
$user = $redis->hGetAll('user:1001');
print_r($user);

// 批量设置
$redis->hMSet('user:1002', [
'name' => '李四',
'age' => 35,
'email' => 'lisi@test.com',
]);

// 字段是否存在
echo "存在name: " . ($redis->hExists('user:1002', 'name') ? '是' : '否') . "\n";

// 获取所有键和值
$fields = $redis->hKeys('user:1001');
$values = $redis->hVals('user:1001');
print_r($fields);
print_r($values);

// 计数器
$redis->hIncrBy('user:1001', 'login_count', 1);
echo "登录次数: " . $redis->hGet('user:1001', 'login_count') . "\n";
?>
```

Set适合做集合运算。

```php
// 用户标签
$redis->sAdd('user:1:tags', 'PHP', 'JavaScript', 'MySQL', 'Redis');
$redis->sAdd('user:2:tags', 'PHP', 'Python', 'Docker', 'Redis');

// 共同标签(交集)
$commonTags = $redis->sInter('user:1:tags', 'user:2:tags');
echo "共同标签: " . implode(', ', $commonTags) . "\n";

// 所有标签(并集)
$allTags = $redis->sUnion('user:1:tags', 'user:2:tags');
echo "所有标签: " . implode(', ', $allTags) . "\n";

// 差异标签
$diffTags = $redis->sDiff('user:1:tags', 'user:2:tags');
echo "User1特有: " . implode(', ', $diffTags) . "\n";

// 随机获取成员
$random = $redis->sRandMember('user:1:tags', 2);
echo "随机标签: " . implode(', ', $random) . "\n";

// 集合大小
echo "User1标签数: " . $redis->sCard('user:1:tags') . "\n";
?>
```

Sorted Set(有序集合)适合排行榜场景。

```php
// 游戏排行榜
$redis->zAdd('leaderboard', 9500, '张三');
$redis->zAdd('leaderboard', 8800, '李四');
$redis->zAdd('leaderboard', 9200, '王五');
$redis->zAdd('leaderboard', 7800, '赵六');
$redis->zAdd('leaderboard', 9900, '钱七');

// 获取前3名(从高到低)
$top3 = $redis->zRevRange('leaderboard', 0, 2, true);
echo "排行榜前三:\n";
foreach ($top3 as $player => $score) {
echo " $player: $score分\n";
}

// 获取某人的排名
$rank = $redis->zRevRank('leaderboard', '李四');
echo "李四排名: 第" . ($rank + 1) . "名\n";

// 获取某人的分数
echo "张三分数: " . $redis->zScore('leaderboard', '张三') . "\n";

// 增加分数
$redis->zIncrBy('leaderboard', 100, '王五');
echo "王五加分后: " . $redis->zScore('leaderboard', '王五') . "\n";

// 统计分数区间人数
$count = $redis->zCount('leaderboard', 8000, 9500);
echo "8000-9500分人数: $count\n";
?>
```

Redis的发布订阅模式可以用于消息通知。

```php
// 发布者
function publishMessage(Redis $redis, string $channel, string $message): void
{
$redis->publish($channel, $message);
echo "已发布到频道 $channel: $message\n";
}

$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
publishMessage($redis, 'notifications', '有新订单');
publishMessage($redis, 'notifications', '用户注册成功');
?>
```

Redis的Lua脚本可以在服务端执行原子操作。

```php
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);

// Lua脚本:限流
$rateLimitScript = '
local key = KEYS[1]
local limit = tonumber(ARGV[1])
local window = tonumber(ARGV[2])

local current = redis.call("GET", key)
if current and tonumber(current) >= limit then
return 0
end

redis.call("INCR", key)
redis.call("EXPIRE", key, window)
return 1
';

$redis->eval($rateLimitScript, ['rate_limit:api', 100, 60], 1);
echo "请求通过\n";
?>

分布式锁也是Redis的常见用途。

class RedisLock
{
private Redis $redis;
private string $prefix = 'lock:';
private int $defaultTTL = 10;

public function __construct(Redis $redis)
{
$this->redis = $redis;
}

public function acquire(string $key, int $ttl = null): ?string
{
$ttl = $ttl ?: $this->defaultTTL;
$lockKey = $this->prefix . $key;
$token = bin2hex(random_bytes(16));

// SET NX EX 原子操作
$result = $this->redis->set($lockKey, $token, ['NX', 'EX' => $ttl]);

if ($result) {
return $token;
}

return null;
}

public function release(string $key, string $token): bool
{
$lockKey = $this->prefix . $key;

// Lua脚本保证原子性:只有持有锁的人才能释放
$script = '
if redis.call("GET", KEYS[1]) == ARGV[1] then
return redis.call("DEL", KEYS[1])
else
return 0
end
';

return (bool)$this->redis->eval($script, [$lockKey, $token], 1);
}

public function withLock(string $key, callable $callback, int $ttl = null): mixed
{
$token = $this->acquire($key, $ttl);

if ($token === null) {
throw new RuntimeException("无法获取锁: $key");
}

try {
return $callback();
} finally {
$this->release($key, $token);
}
}
}

$redis = new Redis();
$redis->connect('127.0.0.1', 6379);

$lock = new RedisLock($redis);

try {
$lock->withLock('process:order:123', function () {
echo "处理订单中...\n";
sleep(1);
echo "订单处理完成\n";
return ['status' => 'success'];
});
} catch (RuntimeException $e) {
echo "错误: {$e->getMessage()}\n";
}
?>
```

Redis在实际项目中的性能优势很明显。但要注意内存管理,设置合理的过期策略。还有持久化配置,RDB和AOF各有优劣。数据结构的选用也要看具体场景,不是所有数据都适合放Redis。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/1 11:21:59

PHP与MySQL数据库实战指南

PHP与MySQL数据库实战指南PHP和MySQL是经典搭档。从最早的mysql扩展到mysqli再到PDO,PHP连接MySQL的方式一直在进化。今天说说在实际项目中怎么用好这对组合。首先说连接方式。PDO是目前的首选,它支持多种数据库,使用预处理语句天然防止SQL注…

作者头像 李华
网站建设 2026/6/1 11:19:13

OBS多路推流实战指南:突破单平台限制的直播解决方案

OBS多路推流实战指南:突破单平台限制的直播解决方案 【免费下载链接】obs-multi-rtmp OBS複数サイト同時配信プラグイン 项目地址: https://gitcode.com/gh_mirrors/ob/obs-multi-rtmp 在当今多平台直播时代,内容创作者面临的最大挑战之一就是如何…

作者头像 李华
网站建设 2026/6/1 11:19:00

掌握后端开发的核心技能:构建高效稳定系统的秘诀

在当今数字化时代,后端开发作为支撑各类应用和系统运行的核心力量,其重要性不言而喻。无论是电商平台、社交网络还是企业管理系统,背后都离不开强大而稳定的后端支持。掌握后端开发的核心技能,不仅是提升个人技术能力的关键&#…

作者头像 李华
网站建设 2026/6/1 11:18:57

LLM推理优化与KV Cache机制深度解析

LLM推理优化与KV Cache机制深度解析从Transformer注意力计算到生产级推理加速,一篇讲透大模型推理优化的核心技术导语 在大模型落地过程中,推理延迟和显存占用是工程师面临的首要挑战。当模型参数从7B扩展到70B甚至更大,如何让推理速度提升10…

作者头像 李华
网站建设 2026/6/1 11:17:23

如何彻底解决Switch手柄问题:Joy-Con Toolkit完整指南

如何彻底解决Switch手柄问题:Joy-Con Toolkit完整指南 【免费下载链接】jc_toolkit Joy-Con Toolkit 项目地址: https://gitcode.com/gh_mirrors/jc/jc_toolkit Joy-Con Toolkit是一款功能强大的开源工具,专门为任天堂Switch手柄提供全面的优化和…

作者头像 李华