Redis 从基础到实战

文章目录

  • [一、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 需手动开启:​

  1. 打开配置文件 sudo vim /etc/redis/redis.conf
  2. 找到 appendonly no,改为 appendonly yes
  3. 重启服务 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 

可以看到:第一次查询走数据库并写入缓存,第二次直接从缓存读取,完美实现 "缓存优先" 逻辑。

相关推荐
呆呆小金人3 小时前
SQL优化实战:从慢查询到高效查询
大数据·数据库·数据仓库·sql·数据库开发·etl·etl工程师
爱隐身的官人3 小时前
SQL注入过滤绕过fuzz字典
数据库·sql
小马哥编程4 小时前
【软考架构】案例分析-系统设计与建模:数据流图DFD与数据字典
java·数据库·架构·统一建模语言
sibylyue4 小时前
Spring编程式事务和声明式事务
java·数据库·mysql
人类二号4 小时前
MySQL安装及启用(社区版)
数据库·mysql
StarRocks_labs5 小时前
告别 Hadoop,拥抱 StarRocks!政采云数据平台升级之路
大数据·数据库·starrocks·hadoop·存算分离
重整旗鼓~5 小时前
32.图片上传功能
java·redis
Azure++5 小时前
Windows配置jar、redis、nginx开机自启
windows·redis·jar
骇客野人11 小时前
mysql笛卡尔积怎么形成的怎么避免笛卡尔积
数据库·mysql