目录

前言

一、今日完结任务

二、今日核心知识点总结

1. NoSQL与关系型数据库对比

2. Redis核心特性

3. 为什么使用Redis?

三、遇到的问题:连接Redis服务失败

1. 问题描述

2. 问题分析

3. 解决方案

四、今日实战收获

1. Redis五种数据结构实战

1.1 String(字符串类型)

1.2 Hash(哈希类型)

1.3 List(列表类型)

1.4 Set(集合类型)

1.5 SortedSet(有序集合)

2. Redis通用命令

3. Redis桌面客户端使用

4. StringRedisTemplate实战

4.1 SpringBoot项目集成

4.2 基本使用示例

4.3 对象存储的最佳实践

4.4 事务操作

五、小知识点总结

1. Redis键的命名规范

2. 数据库选择

3. 数据类型选择策略

4. 命令使用技巧

5. StringRedisTemplate优势

6. 常用操作接口

总结


前言

        时隔一周,今天我开始学习企业级项目中必不可少的缓存中间件——Redis。在前几天完成了苍穹外卖项目后,我深刻体会到数据访问性能的重要性,而Redis作为高性能的内存数据库,正是解决高并发访问、数据缓存等问题的利器。

        今天主要学习Redis的基础概念、安装部署以及基本数据结构操作,为后续在实际项目中应用Redis打下坚实基础。


一、今日完结任务

  1. ✅ 学习NoSQL数据库概念及其与关系型数据库的区别

  2. ✅ 了解Redis的特点和应用场景

  3. ✅ 掌握Windows环境下Redis的安装与配置

  4. ✅ 学习Redis的5种基本数据结构及其常用命令

  5. ✅ 使用Redis可视化客户端进行基本操作


二、今日核心知识点总结

1. NoSQL与关系型数据库对比

NoSQL特点:

  • 非结构化:数据格式灵活,没有严格的表结构约束

  • 无关联性:数据间没有外键关联,关系维护依赖业务逻辑

  • 高性能:基于内存操作,读写速度快,适合高并发场景

  • 可扩展性强:支持水平扩展,适合海量数据存储

核心对比:

对比维度 关系型数据库 NoSQL数据库
数据结构 结构化,表格式 非结构化,灵活
数据关联 表间关联(外键) 无关联或业务维护
查询语言 SQL(标准统一) 各数据库不同
事务支持 ACID原则 基本一致或不支持
存储方式 磁盘存储,有IO 内存为主,速度快
扩展方式 垂直扩展(主从) 水平扩展(分片)

2. Redis核心特性

  • 内存存储:数据主要存储在内存中,读写性能极高

  • 单线程模型:命令执行具备原子性,避免线程安全问题

  • 丰富的数据结构:支持String、Hash、List、Set、SortedSet等

  • 持久化支持:可将内存数据保存到磁盘,防止数据丢失

  • 高可用性:支持主从复制、哨兵模式、集群部署

  • 多语言客户端:Java、Python、Go等主流语言都支持

3. 为什么使用Redis?

        主要是因为 Redis 具备「高性能」「高并发」两种特性。

        1. Redis 具备高性能

        假如用户第一次访问 MySQL 中的某些数据。这个过程会比较慢,因为是从硬盘上读取的。将该用户访问的数据缓存在 Redis 中,这样下一次再访问这些数据的时候就可以直接从缓存中获取了,操作 Redis 缓存就是直接操作内存,所以速度相当

        2. Redis 具备高并发

        单台设备的 Redis 的 QPS(Query Per Second,每秒钟处理完请求的次数) 是 MySQL 的 10 倍,Redis 单机的 QPS 能轻松破 10w,而 MySQL 单机的 QPS 很难破 1w。

        所以,直接访问 Redis 能够承受的请求是远远大于直接访问 MySQL 的,所以我们可以考虑把数据库中的部分数据转移到缓存中去,这样用户的一部分请求会直接到缓存这里而不用经过数据库。


三、遇到的问题:连接Redis服务失败

1. 问题描述

在Windows中安装Redis后,使用Redis客户端连接时出现以下错误:

Could not connect to Redis at 127.0.0.1:6379: Connection refused

2. 问题分析

  1. Redis服务未启动

  2. 防火墙阻止了6379端口

  3. Redis配置绑定了特定IP地址(默认只允许本地访问)

3. 解决方案

步骤1:保证Redis在后台运行

步骤2:修改Redis配置文件
编辑redis.conf文件,关键配置修改:

# 允许所有IP访问(生产环境需谨慎)
bind 0.0.0.0
# 以守护进程方式运行
daemonize yes
# 设置密码(可选)
requirepass 123456

步骤3:重启Redis服务

在Redis安装目录下启动cmd输入

# 指定配置文件启动
redis-server.exe redis.windows.conf

步骤4:测试连接

# 使用密码连接
redis-cli -h 127.0.0.1 -p 6379 -a 123456
# 测试连接
ping  # 应返回PONG

四、今日实战收获

1. Redis五种数据结构实战

1.1 String(字符串类型)

        String类型,也就是字符串类型,是Redis中最简单的存储类型。

适用场景:缓存、计数器、分布式锁

# 设置值
SET name "张三"
# 获取值
GET name
# 设置过期时间(10秒)
SETEX token 10 "abc123"
# 数值递增
INCR views  # 自增1
INCRBY views 5  # 自增5
1.2 Hash(哈希类型)

        Hash类型,也叫散列,其value是一个无序字典,类似于Java中的HashMap结构。

适用场景:存储对象信息,如用户信息、商品详情

# 设置单个字段
HSET user:1001 name "李四"
HSET user:1001 age 25
# 批量设置字段
HMSET user:1002 name "王五" age 30 city "北京"
# 获取所有字段
HGETALL user:1001
# 获取指定字段
HGET user:1001 name
# 字段递增
HINCRBY user:1001 age 1
1.3 List(列表类型)

        Redis中的List类型与Java中的LinkedList类似,可以看做是一个双向链表结构。既可以支持正向检索和也可以支持反向检索。

适用场景:消息队列、最新列表、历史记录

# 左侧插入
LPUSH messages "msg1" "msg2"
# 右侧插入
RPUSH messages "msg3"
# 左侧弹出
LPOP messages
# 右侧弹出
RPOP messages
# 获取范围元素
LRANGE messages 0 2
1.4 Set(集合类型)

        Redis的Set结构与Java中的HashSet类似,可以看做是一个value为null的HashMap。因为也是一个hash表,因此具备与HashSet类似的特征:

适用场景:标签、共同好友、随机推荐

# 添加元素
SADD tags "Java" "Redis" "MySQL"
# 查看所有元素
SMEMBERS tags
# 删除元素
SREM tags "MySQL"
# 集合运算
SADD set1 "A" "B" "C"
SADD set2 "B" "C" "D"
# 交集
SINTER set1 set2  # 返回: B C
# 并集
SUNION set1 set2  # 返回: A B C D
# 差集
SDIFF set1 set2   # 返回: A
1.5 SortedSet(有序集合)

        Redis的SortedSet是一个可排序的set集合,与Java中的TreeSet有些类似,但底层数据结构却差别很大。SortedSet中的每一个元素都带有一个score属性,可以基于score属性对元素排序,底层的实现是一个跳表(SkipList)加 hash表。

适用场景:排行榜、带权重的队列

# 添加带分值的元素
ZADD leaderboard 100 "张三" 95 "李四" 85 "王五"
# 按分值升序获取(0到2名)
ZRANGE leaderboard 0 2
# 按分值降序获取(0到2名)
ZREVRANGE leaderboard 0 2
# 获取元素排名(从0开始)
ZRANK leaderboard "李四"
# 获取元素分值
ZSCORE leaderboard "张三"

2. Redis通用命令

# 查看所有key(生产环境慎用)
KEYS *
# 查看以user开头的key
KEYS user:*
# 判断key是否存在
EXISTS user:1001
# 设置key过期时间(秒)
EXPIRE token 3600
# 查看key剩余生存时间
TTL token
# 删除key
DEL user:1001
# 选择数据库(0-15)
SELECT 1

3. Redis桌面客户端使用

安装了Another Redis Desktop Manager,通过图形界面:

  • 直观查看所有key和value

  • 支持多种数据结构可视化展示

  • 可直接编辑、删除数据

  • 支持批量操作和导入导出

4. StringRedisTemplate实战

4.1 SpringBoot项目集成

Maven依赖:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-pool2</artifactId>
</dependency>

配置文件application.yml:

spring:
  redis:
    host: localhost
    port: 6379
    password: 123456
    lettuce:
      pool:
        max-active: 8
        max-idle: 8
        min-idle: 0
        max-wait: 100ms
4.2 基本使用示例
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

@Service
public class RedisService {
    
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    
    // 1. String类型操作
    public void stringOperations() {
        // 设置值
        stringRedisTemplate.opsForValue().set("username", "张三");
        
        // 获取值
        String username = stringRedisTemplate.opsForValue().get("username");
        
        // 设置过期时间
        stringRedisTemplate.opsForValue().set("token", "abc123", 3600, TimeUnit.SECONDS);
        
        // 递增操作
        stringRedisTemplate.opsForValue().increment("pageView");
        stringRedisTemplate.opsForValue().increment("pageView", 5);
    }
    
    // 2. Hash类型操作
    public void hashOperations() {
        // 设置hash字段
        stringRedisTemplate.opsForHash().put("user:1001", "name", "李四");
        stringRedisTemplate.opsForHash().put("user:1001", "age", "25");
        
        // 获取hash字段
        String name = (String) stringRedisTemplate.opsForHash().get("user:1001", "name");
        
        // 获取所有字段
        Map<Object, Object> user = stringRedisTemplate.opsForHash().entries("user:1001");
    }
    
    // 3. List类型操作
    public void listOperations() {
        // 左侧插入
        stringRedisTemplate.opsForList().leftPush("messages", "Hello");
        stringRedisTemplate.opsForList().leftPush("messages", "World");
        
        // 获取范围元素
        List<String> messages = stringRedisTemplate.opsForList().range("messages", 0, -1);
    }
    
    // 4. Set类型操作
    public void setOperations() {
        // 添加元素
        stringRedisTemplate.opsForSet().add("tags", "Java", "Redis", "MySQL");
        
        // 获取所有元素
        Set<String> tags = stringRedisTemplate.opsForSet().members("tags");
    }
}
4.3 对象存储的最佳实践

使用JSON序列化存储对象:

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;

@Service
public class UserService {
    
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    
    private final ObjectMapper objectMapper = new ObjectMapper();
    
    // 存储对象(手动序列化为JSON)
    public void saveUser(User user) throws JsonProcessingException {
        String userJson = objectMapper.writeValueAsString(user);
        String key = "user:" + user.getId();
        stringRedisTemplate.opsForValue().set(key, userJson);
        
        // 可以设置过期时间
        stringRedisTemplate.expire(key, 1, TimeUnit.HOURS);
    }
    
    // 获取对象(手动反序列化)
    public User getUser(Long userId) throws JsonProcessingException {
        String key = "user:" + userId;
        String userJson = stringRedisTemplate.opsForValue().get(key);
        
        if (userJson != null) {
            return objectMapper.readValue(userJson, User.class);
        }
        return null;
    }
    
    // 存储对象到Hash
    public void saveUserToHash(User user) {
        String key = "user:hash:" + user.getId();
        Map<String, String> userMap = new HashMap<>();
        userMap.put("id", user.getId().toString());
        userMap.put("name", user.getName());
        userMap.put("age", user.getAge().toString());
        userMap.put("email", user.getEmail());
        
        stringRedisTemplate.opsForHash().putAll(key, userMap);
    }
}
4.4 事务操作
public void transactionalOperations() {
    // 使用SessionCallback执行事务
    stringRedisTemplate.execute(new SessionCallback<List<Object>>() {
        @Override
        public List<Object> execute(RedisOperations operations) throws DataAccessException {
            operations.multi(); // 开启事务
            
            operations.opsForValue().set("key1", "value1");
            operations.opsForValue().set("key2", "value2");
            operations.opsForValue().increment("counter");
            
            return operations.exec(); // 执行事务
        }
    });
}

五、小知识点总结

1. Redis键的命名规范

# 使用冒号分隔形成层级结构
# 项目名:数据类型:ID
user:1001:info
product:2001:detail
order:3001:items

2. 数据库选择

  • Redis默认有16个数据库(0-15)

  • 不同数据库完全隔离,key可以重复

  • 生产环境建议使用默认的0号库

3. 数据类型选择策略

  • String:简单KV,如缓存、计数器

  • Hash对象类型,如用户信息

  • List有序可重复,如消息队列

  • Set无序不重复,如标签系统

  • SortedSet有序不重复,如排行榜

4. 命令使用技巧

  • 批量操作:使用MSET、HMSET、SADD等批量命令,减少网络开销

  • 管道技术:一次性发送多个命令,提升执行效率

  • 原子操作:INCR、DECR等命令是原子性的,适合计数器场景

5. StringRedisTemplate优势

  1. 避免序列化问题:不存储类信息,不会因类路径变化导致反序列化失败

  2. 跨语言兼容:存储的是JSON字符串,其他语言也可以读取

  3. 便于调试:Redis中可以直接查看存储的内容

  4. 节省内存:不存储额外的类信息,内存占用更小

6. 常用操作接口

总结

        今天系统地学习了Redis的基础知识,从NoSQL概念到Redis具体安装配置,再到5种核心数据结构的操作命令。通过实践操作,我深刻体会到Redis作为内存数据库(缓存)的独特优势:

  1. 性能卓越:内存操作带来的毫秒级响应,完全满足高并发场景需求

  2. 数据结构丰富:不仅仅是简单的KV存储,多种数据结构能灵活应对不同业务场景

  3. 操作原子性:单线程模型保证了命令执行的原子性,简化了并发控制

  4. 部署灵活:支持多种集群模式,能满足不同规模的业务需求


Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐