文章目录
- [一、Redis 是什么?为什么要用它?](#一、Redis 是什么?为什么要用它?)
- [二、第一步:Redis 安装(不同系统指南)](#二、第一步:Redis 安装(不同系统指南))
-
- [1. Ubuntu 系统](#1. Ubuntu 系统)
- [2. Mac 系统](#2. Mac 系统)
- [三、核心:Redis 5 种基本数据类型及用法](#三、核心:Redis 5 种基本数据类型及用法)
-
- [1. String(字符串):最基础的键值对](#1. String(字符串):最基础的键值对)
- [2. Hash(哈希):存 "对象" 更方便](#2. Hash(哈希):存 “对象” 更方便)
- [3. List(列表):有序的 "队列 / 栈"](#3. List(列表):有序的 “队列 / 栈”)
- [4. Set(集合):自动去重的 "篮子"](#4. Set(集合):自动去重的 “篮子”)
- [5. ZSet(有序集合):带 "分数" 的排行榜](#5. ZSet(有序集合):带 “分数” 的排行榜)
- [四、Redis 常用操作:连接、持久化、过期设置](#四、Redis 常用操作:连接、持久化、过期设置)
-
- [1. Ubuntu 下 Redis 配置修改(可选)](#1. Ubuntu 下 Redis 配置修改(可选))
- [2. 远程连接 Redis](#2. 远程连接 Redis)
- [3. 数据持久化(Ubuntu 默认配置)](#3. 数据持久化(Ubuntu 默认配置))
- [4. 查看 / 删除键(通用命令)](#4. 查看 / 删除键(通用命令))
- [五、实战:用 Redis 存用户缓存(C++ + Ubuntu 示例)](#五、实战:用 Redis 存用户缓存(C++ + Ubuntu 示例))
-
- [1. 第一步:Ubuntu 安装 hiredis 库](#1. 第一步:Ubuntu 安装 hiredis 库)
- [2. 完整代码示例](#2. 完整代码示例)
- [3. 编译与运行](#3. 编译与运行)
一、Redis 是什么?为什么要用它?
Redis(Remote Dictionary Server)是一款开源的内存数据库,简单说就是 "把数据存在内存里,取数据超快" 的工具。它的核心优势很突出:
- 速度快:内存读写,每秒能处理十几万请求;
- 用途广:能做缓存、会话存储、消息队列、排行榜等;
- 支持多数据类型:不止存键值对,还能存列表、哈希、集合等。
日常开发中,比如 "用户登录后的会话信息存储""商品详情页缓存(减少数据库压力)""点赞排行榜",都能用 Redis 轻松实现~
二、第一步:Redis 安装(不同系统指南)
Ubuntu 系统下用 apt 包管理器安装更高效:
1. Ubuntu 系统
bash
# 1. 先更新apt包索引(确保能获取最新版本)
sudo apt update
# 2. 安装Redis服务器和客户端
sudo apt install -y redis-server redis-tools
# 3. 启动Redis服务并设置开机自启
sudo systemctl start redis-server
sudo systemctl enable redis-server # 开机自动启动
# 4. 验证Redis是否启动成功(返回PONG表示正常)
redis-cli ping
# 5. 连接Redis(本地连接直接执行,默认无密码)
redis-cli
2. Mac 系统
直接用 Homebrew,一行搞定:
bash
# 安装
brew install redis
# 启动
brew services start redis
# 连接
redis-cli
三、核心:Redis 5 种基本数据类型及用法
Redis 最常用的就是这 5 种数据类型,每种都有特定场景,记清 "是什么 + 怎么用 + 用在哪" 就够了。
1. String(字符串):最基础的键值对
作用:存单个值(文本、数字都可以),比如验证码、计数器。
常用命令:
bash
# 存值:SET 键 值
SET code "123456" # 存验证码
# 取值:GET 键
GET code # 返回 "123456"
# 数字自增(比如统计访问量)
SET view 0
INCR view # view变成1
INCR view # view变成2
# 设置过期时间(比如验证码10分钟失效)
SET code "654321" EX 600 # EX表示秒,600秒=10分钟
场景:存储短信验证码、用户 ID 对应的昵称、接口访问计数器。
2. Hash(哈希):存 "对象" 更方便
作用:类似 JSON 对象,键里套 "字段 - 值",适合存结构化数据(比如用户信息)。
常用命令:
bash
# 存对象:HSET 键 字段1 值1 字段2 值2
HSET user:100 name "张三" age 25 gender "男"
# 取单个字段:HGET 键 字段
HGET user:100 name # 返回 "张三"
# 取所有字段和值:HGETALL 键
HGETALL user:100 # 返回 ["name","张三","age","25","gender","男"]
# 删字段:HDEL 键 字段
HDEL user:100 gender
场景:存储用户信息、商品详情(比如商品名、价格、库存)。
3. List(列表):有序的 "队列 / 栈"
作用:按插入顺序排序的字符串集合,可从两端操作,能当队列(先进先出)或栈(先进后出)。
常用命令:
bash
# 从左边加元素(类似栈的push)
LPUSH msg "早安"
LPUSH msg "午安" # 此时列表是 ["午安","早安"]
# 从右边加元素
RPUSH msg "晚安" # 列表变成 ["午安","早安","晚安"]
# 从左边删元素(类似栈的pop)
LPOP msg # 删除并返回 "午安",列表剩 ["早安","晚安"]
# 查看列表内容:LRANGE 键 起始索引 结束索引(-1表示最后一个)
LRANGE msg 0 -1 # 返回 ["早安","晚安"]
场景:消息队列(比如订单通知)、最新消息列表(比如朋友圈点赞列表)。
4. Set(集合):自动去重的 "篮子"
作用:无序的字符串集合,自动去重,还能做交集、并集(比如找共同好友)。
常用命令:
bash
# 加元素:SADD 键 元素1 元素2
SADD user:100:tags "篮球" "游戏" "音乐"
SADD user:100:tags "游戏" # 重复元素,不会新增
# 看所有元素:SMEMBERS 键
SMEMBERS user:100:tags # 返回 ["篮球","游戏","音乐"](顺序不固定)
# 判重:SISMEMBER 键 元素(存在返回1,不存在0)
SISMEMBER user:100:tags "足球" # 返回 0
# 交集(找共同标签,比如user100和user200的共同爱好)
SADD user:200:tags "游戏" "电影"
SINTER user:100:tags user:200:tags # 返回 ["游戏"]
场景:用户标签(去重)、共同好友 / 关注、抽奖(随机取元素)。
5. ZSet(有序集合):带 "分数" 的排行榜
作用:在 Set 基础上给每个元素加 "分数",按分数排序,天生适合做排行榜。
常用命令:
bash
# 加元素:ZADD 键 分数1 元素1 分数2 元素2
ZADD rank:article 100 "文章A" 200 "文章B" 150 "文章C"
# 按分数升序看:ZRANGE 键 起始 结束(WITHSCORES显示分数)
ZRANGE rank:article 0 -1 WITHSCORES # 返回 ["文章A",100,"文章C",150,"文章B",200]
# 按分数降序看(排行榜常用)
ZREVRANGE rank:article 0 -1 WITHSCORES # 返回 ["文章B",200,"文章C",150,"文章A",100]
# 改分数(比如文章A点赞数+10)
ZINCRBY rank:article 10 "文章A" # 文章A分数变成110
场景:文章点赞排行榜、用户积分排行榜、直播礼物榜。
四、Redis 常用操作:连接、持久化、过期设置
1. Ubuntu 下 Redis 配置修改(可选)
默认 Redis 仅允许本地连接,若需远程访问,可修改配置文件:
bash
# 1. 用vim打开Redis配置文件
sudo vim /etc/redis/redis.conf
# 2. 找到并修改以下内容:
# (1)注释掉bind 127.0.0.1(允许所有IP访问)
# bind 127.0.0.1 ::1
# (2)关闭保护模式(允许远程连接)
protected-mode no
# (3)(可选)设置密码(找到requirepass,去掉#并设置密码)
requirepass your_password # 替换成你的密码
# 3. 保存退出后重启Redis服务
sudo systemctl restart redis-server
2. 远程连接 Redis
bash
# 格式:redis-cli -h 服务器IP -p 端口 -a 密码
redis-cli -h 192.168.1.100 -p 6379 -a your_password
3. 数据持久化(Ubuntu 默认配置)
Ubuntu 下安装的 Redis 默认开启 RDB 持久化,AOF 需手动开启:
- 打开配置文件
sudo vim /etc/redis/redis.conf; - 找到
appendonly no,改为appendonly yes; - 重启服务
sudo systemctl restart redis-server。
4. 查看 / 删除键(通用命令)
bash
# 查看所有键(生产环境少用,会阻塞)
KEYS * # 返回所有键名
# 查看键类型
TYPE user:100 # 返回 hash
# 删除键
DEL code # 删除code这个键
五、实战:用 Redis 存用户缓存(C++ + Ubuntu 示例)
Ubuntu 下用 hiredis 库操作 Redis 更便捷,下面实现 "先查缓存、再查数据库" 逻辑,减少数据库压力。
1. 第一步:Ubuntu 安装 hiredis 库
bash
五、实战:用 Redis 存用户缓存(C+++Ubuntu 示例)
Ubuntu 下用hiredis库操作 Redis 更便捷,下面实现 "先查缓存、再查数据库" 逻辑,减少数据库压力。
1. 第一步:Ubuntu 安装 hiredis 库
2. 完整代码示例
cpp
#include <iostream>
#include <string>
#include <unordered_map>
#include <hiredis/hiredis.h> // 引入hiredis头文件
// 1. 封装Redis连接工具(自动释放连接,避免内存泄漏)
class RedisClient {
private:
redisContext* conn; // Redis连接句柄
public:
// 构造函数:连接Redis(支持带密码连接)
RedisClient(const std::string& host, int port, const std::string& password = "") {
// 建立连接
conn = redisConnect(host.c_str(), port);
if (conn == nullptr || conn->err) {
if (conn) {
std::cerr << "Redis连接失败:" << conn->errstr << std::endl;
redisFree(conn); // 释放连接
conn = nullptr;
} else {
std::cerr << "Redis连接失败:无法创建连接对象" << std::endl;
}
return;
}
// 如果有密码,执行AUTH认证
if (!password.empty()) {
redisReply* reply = (redisReply*)redisCommand(conn, "AUTH %s", password.c_str());
if (reply == nullptr || reply->type == REDIS_REPLY_ERROR) {
std::cerr << "Redis认证失败:" << (reply ? reply->str : "未知错误") << std::endl;
freeReplyObject(reply); // 释放回复内存
redisFree(conn);
conn = nullptr;
return;
}
freeReplyObject(reply); // 释放认证回复
}
std::cout << "Redis连接成功!" << std::endl;
}
// 析构函数:释放连接
~RedisClient() {
if (conn != nullptr) {
redisFree(conn);
conn = nullptr;
}
}
// 执行Redis命令(返回回复,调用者需手动释放freeReplyObject)
redisReply* executeCommand(const char* format, ...) {
if (conn == nullptr) {
std::cerr << "Redis连接未初始化,无法执行命令" << std::endl;
return nullptr;
}
va_list args;
va_start(args, format);
redisReply* reply = (redisReply*)redisvCommand(conn, format, args);
va_end(args);
if (reply == nullptr || reply->type == REDIS_REPLY_ERROR) {
std::cerr << "命令执行失败:" << (reply ? reply->str : "未知错误") << std::endl;
if (reply) {
freeReplyObject(reply);
return nullptr;
}
}
return reply;
}
// 判断连接是否有效
bool isConnected() const {
return conn != nullptr;
}
};
// 2. 模拟从数据库查询用户信息(实际项目替换为SQL查询)
std::unordered_map<std::string, std::string> get_user_from_db(int user_id) {
// 模拟数据库中的用户数据
std::unordered_map<std::string, std::string> user_info;
user_info["name"] = "李四";
user_info["age"] = "30";
user_info["phone"] = "13800138000";
std::cout << "从数据库获取用户信息:" << std::endl;
return user_info;
}
// 3. 核心逻辑:先查缓存,再查数据库,查到后存缓存
std::unordered_map<std::string, std::string> get_user(RedisClient& redis_client, int user_id) {
// 缓存键名规范:业务:ID:类型(如user:101:info)
std::string cache_key = "user:" + std::to_string(user_id) + ":info";
std::unordered_map<std::string, std::string> user_info;
// 第一步:查询缓存(HGETALL获取哈希所有字段和值)
redisReply* reply = redis_client.executeCommand("HGETALL %s", cache_key.c_str());
if (reply != nullptr) {
// HGETALL返回的是数组,长度为2*N(字段1、值1、字段2、值2...)
if (reply->type == REDIS_REPLY_ARRAY && reply->elements > 0) {
for (size_t i = 0; i < reply->elements; i += 2) {
std::string field = reply->element[i]->str;
std::string value = reply->element[i+1]->str;
user_info[field] = value;
}
freeReplyObject(reply); // 释放回复内存
std::cout << "从缓存获取用户信息:" << std::endl;
return user_info;
}
freeReplyObject(reply); // 释放空回复
}
// 第二步:缓存未命中,查询数据库
user_info = get_user_from_db(user_id);
// 第三步:将数据库数据存入缓存(HSET+EXPIRE设置1小时过期)
if (!user_info.empty() && redis_client.isConnected()) {
// 执行HSET命令:HSET user:101:info name "李四" age "30" phone "13800138000"
redisReply* hset_reply = redis_client.executeCommand(
"HSET %s name %s age %s phone %s",
cache_key.c_str(),
user_info["name"].c_str(),
user_info["age"].c_str(),
user_info["phone"].c_str()
);
if (hset_reply != nullptr) {
freeReplyObject(hset_reply); // 释放HSET回复
}
// 设置缓存过期时间(3600秒=1小时,避免数据过时)
redisReply* expire_reply = redis_client.executeCommand("EXPIRE %s 3600", cache_key.c_str());
if (expire_reply != nullptr) {
freeReplyObject(expire_reply); // 释放EXPIRE回复
}
std::cout << "用户信息已存入缓存(1小时过期)" << std::endl;
}
return user_info;
}
// 4. 打印用户信息(辅助函数)
void print_user_info(const std::unordered_map<std::string, std::string>& user_info) {
for (const auto& [field, value] : user_info) {
std::cout << field << ": " << value << " ";
}
std::cout << std::endl;
}
int main() {
// 初始化Redis客户端(Ubuntu本地连接,默认port=6379,密码填你设置的,无则空)
RedisClient redis_client("127.0.0.1", 6379, "your_password");
if (!redis_client.isConnected()) {
return 1; // 连接失败,退出程序
}
// 测试1:第一次查询(缓存未命中,走数据库)
std::cout << "=== 第一次查询用户101 ===" << std::endl;
auto user1 = get_user(redis_client, 101);
print_user_info(user1);
// 测试2:第二次查询(缓存命中,走缓存)
std::cout << "\n=== 第二次查询用户101 ===" << std::endl;
auto user2 = get_user(redis_client, 101);
print_user_info(user2);
return 0;
}
3. 编译与运行
bash
# 1. 保存代码为redis_user_cache.cpp
# 2. 编译(链接hiredis库,-lhiredis不可少)
g++ redis_user_cache.cpp -o redis_user_cache -lhiredis
# 3. 运行程序(若设置了Redis密码,需在代码中填对)
./redis_user_cache
运行结果
bash
Redis连接成功!
=== 第一次查询用户101 ===
从数据库获取用户信息:
用户信息已存入缓存(1小时过期)
name: 李四 age: 30 phone: 13800138000
=== 第二次查询用户101 ===
从缓存获取用户信息:
name: 李四 age: 30 phone: 13800138000
可以看到:第一次查询走数据库并写入缓存,第二次直接从缓存读取,完美实现 "缓存优先" 逻辑。