Redis快速入门以及集成于springboot

Redis快速入门

Redis(Remote Dictionary Server)是一款 开源、高性能、基于内存的键值对(Key-Value)数据库,支持多种数据结构,常被用于缓存、会话存储、消息队列、实时统计等场景。以下是 Redis 的核心知识点、使用场景及关键特性,帮你快速掌握核心内容:

一、Redis 核心特性

  1. 基于内存,速度极快:数据主要存储在内存中,读写性能峰值可达 10 万 + QPS,延迟低至亚毫秒级(适合高频访问场景)。
  2. 支持多种数据结构:不止字符串(String),还支持哈希(Hash)、列表(List)、集合(Set)、有序集合(Sorted Set)、位图(Bitmap)、地理哈希(Geo)等,灵活适配不同业务。
  3. 持久化机制:支持两种持久化方式,避免内存数据丢失:
    • RDB(Redis Database):定时快照(如每 5 分钟 + 10 次写入),适合备份、灾难恢复(恢复速度快,但可能丢失最后一次快照后的 data)。
    • AOF(Append Only File):记录每一条写命令(如每秒刷盘),数据完整性更高(最多丢失 1 秒数据),但文件体积大、恢复慢。
    • 生产环境常搭配使用(RDB 做备份,AOF 保证数据安全)
  4. 高可用与分布式
    • 主从复制(Master-Slave):主节点写、从节点读,实现读写分离、负载均衡。
    • 哨兵(Sentinel):监控主从节点,自动故障转移(主节点挂了,从节点晋升为主)。
    • Redis Cluster:分片集群(默认 16384 个哈希槽),支持水平扩容(最多 1000+ 节点),解决单节点内存上限问题。
  5. 原子操作与事务:支持单个命令的原子性(如 incr 自增),也支持 MULTI/EXEC 事务(批量命令要么全执行,要么全不执行,但不支持回滚)。
  6. 支持过期键与淘汰策略
    • 键可以设置过期时间(EXPIRE key seconds),自动删除。
    • 内存满时,触发淘汰策略(如 LRU 最近最少使用、LFU 最不经常使用、随机淘汰等)。

二、核心数据结构及使用场景

数据结构核心特点常用命令典型场景
String(字符串)二进制安全(可存图片 / 序列化数据),支持自增 / 自减、拼接SET、GET、INCR、APPEND、EXPIRE缓存用户信息、计数器(文章阅读量)、分布式锁(SET NX EX)
Hash(哈希)键值对集合(类似 Java Map),支持单个字段读写HSET、HGET、HMGET、HDEL存储对象(如用户信息:id -> {name: "xxx", age: 20})
List(列表)有序、可重复,支持首尾插入 / 删除(双向链表)LPUSH、RPUSH、LPOP、RPOP、LRANGE消息队列(简单 FIFO)、最新列表(如朋友圈最新动态)
Set(集合)无序、不可重复,支持交集 / 并集 / 差集SADD、SMEMBERS、SINTER(交集)、SUNION(并集)好友关系(共同好友)、去重(抽奖用户去重)
Sorted Set(有序集合)不可重复,每个元素关联分数(score),按分数排序ZADD、ZRANGE、ZSCORE、ZREVRANK排行榜(如游戏积分排名)、带权重的消息队列
Bitmap(位图)以位为单位存储(节省空间),支持位运算SETBIT、GETBIT、BITCOUNT签到统计(1 代表签到,0 代表未签)、用户在线状态
Geo(地理哈希)存储经纬度,支持距离计算、范围查询GEOADD、GEODIST、GEORADIUS附近的人、外卖骑手定位

三、常见使用场景

  1. 缓存(最核心场景)
    • 缓存热点数据(如商品详情、用户信息),减少数据库访问压力。
    • 缓存穿透防护:缓存空值或使用布隆过滤器。
    • 缓存击穿防护:热点 key 永不过期或加互斥锁。
    • 缓存雪崩防护:过期时间加随机值、主从切换、熔断降级。
  2. 分布式锁
    • 基于 SET key value NX EX seconds 实现(NX:不存在才设置,EX:过期时间),保证分布式系统中资源互斥访问。
    • 进阶:Redlock 算法(解决单节点故障问题)。
  3. 会话存储
    • 存储用户登录会话(如 Session ID -> 用户信息),替代服务器本地 Session,支持分布式部署。
  4. 消息队列
    • 基于 List 的 LPUSH + RPOP 实现简单 FIFO 队列(缺点:无 ack、无持久化保障)。
    • 进阶:使用 Redis Stream(支持 ack、分组消费、持久化)。
  5. 实时统计
    • 计数器:INCR 统计文章阅读量、接口访问量。
    • 位图:统计用户签到天数、活跃用户数。
    • 有序集合:实时排行榜(如直播礼物榜)。
  6. 限流
    • 基于 INCR + EXPIRE 实现固定窗口限流(如 1 分钟最多访问 100 次)。
    • 进阶:滑动窗口限流(结合 ZSet 或 Lua 脚本)。

四、连接到redis

命令行连接:
redis-cli -h 127.0.0.1 -p 6379

  • -h:指定 Redis 服务器 IP(默认 127.0.0.1)。
  • -p:指定端口(默认 6379)。
  • -a:指定密码(简化认证,不推荐生产环境,密码会明文显示)。
  • --raw:输出中文不转义(如存储中文值时)。

测试连接状态

​ping​命令可用于测试连接状态,语法如下

ping

说明:若连接正常,则会返回pong。

图形化客户端:

图形化客户端有很多,我这里使用的是Tiny RDM

如何连接不上看看服务器防火墙和redis的配置,是否bind 0.0.0.0等

五、Redis常用数据类型及命令

一、通用命令

命令说明示例
KEYS 前缀*模糊查键(生产慎用)KEYS user*(查 user 开头的键)
EXISTS 键判断键是否存在(1 = 是,0 = 否)EXISTS user1001
DEL 键1 键2批量删除键DEL user1001 cart200
EXPIRE 键 秒设置过期时间EXPIRE code 60(60 秒过期)
TTL 键查看剩余过期时间(-1 = 永久)TTL code
TYPE 键查看键数据类型TYPE user1001(返回 hash)
keys *  #查询所有的key

keys user* #查询以user开头的所有key

del key1 key2 #删除key1和key2

expire key3 60 #设置key3的过期时间为60秒

ttl key3 #查看key3还有多少时间过期


type key3 #查看key3是什么类型的数据 字符串还是hash、还是list

二、String 字符串

命令说明示例
SET 键 值设置键值(可加 EX 过期)SET name 张三 EX 3600
GET 键获取键值GET name(返回 "张三")
INCR 键整数自增 1(计数器)INCR viewcount(阅读量 + 1)
INCRBY 键 步长自增指定步长INCRBY score 10(分数 + 10)
MSET 键1 值1 键2 值2批量设值MSET a 1 b 2
MGET 键1 键2批量取值MGET a b(返回 [1,2])

三、Hash 哈希(存对象)

命令说明示例
HSET 键 字段 值设置哈希字段值HSET user1001 name 李四 age 25
HGET 键 字段获取哈希字段值HGET user1001 name(返回 "李四")
HGETALL 键获取所有字段和值HGETALL user1001
HDEL 键 字段删除哈希字段HDEL user1001 age
HMGET 键 字段1 字段2批量获取字段值HMGET user1001 name age

四、List 列表(队列 / 栈)

命令说明示例
LPUSH 键 值左侧插入元素(栈:头进头出)LPUSH list1 a b c(结果:c,b,a)
RPUSH 键 值右侧插入元素(队列:尾进头出)RPUSH list1 d(结果:c,b,a,d)
LPOP 键左侧弹出元素LPOP list1(返回 c)
RPOP 键右侧弹出元素RPOP list1(返回 d)
LRANGE 键 起始 结束查看区间元素(0=-1 查所有)LRANGE list1 0 -1(返回 [b,a])

五、Set 集合(无序去重)

命令说明示例
SADD 键 元素1 元素2添加元素(自动去重)SADD usertags java python
SMEMBERS 键查看所有元素SMEMBERS usertags
SINTER 键1 键2求交集(共同元素)SINTER user1tags user2tags
SUNION 键1 键2求并集(所有元素)SUNION user1tags user2tags
SREM 键 元素删除集合元素SREM usertags python

六、Sorted Set 有序集合(排行榜)

命令说明示例
ZADD 键 分数1 元素1添加元素(按分数排序)ZADD rank 95 小明 99 小刚
ZRANGE 键 起始 结束 WITHSCORES升序查看(带分数)ZRANGE rank 0 -1 WITHSCORES
ZREVRANGE 键 起始 结束降序查看(排行榜常用)ZREVRANGE rank 0 2(前 3 名)
ZSCORE 键 元素查看元素分数ZSCORE rank 小刚(返回 99)

七、运维常用

命令说明示例
PING测试连接(返回 PONG = 正常)PING
INFO查看 Redis 状态INFO memory(查内存)
CONFIG GET 配置项查看配置(如密码、端口)CONFIG GET requirepass

SpringBoot整合Redis

Spring Data Redis概述

Spring Data Redis 是 Spring 生态下的 Redis 数据访问框架,核心作用是简化 Redis 的 Java 开发—— 它封装了原生 Redis 客户端(如 Jedis、Lettuce)的复杂操作,提供统一、简洁的 API,让开发者无需关注底层连接管理、序列化、命令封装等细节,专注于业务逻辑。

简单说:原生 Redis 客户端需要手动写连接、序列化、异常处理代码,而 Spring Data Redis 把这些 “重复工作” 做了封装,让你用类似操作数据库的方式操作 Redis。

一、添加依赖

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

二、配置application.yml文件

spring:
  data:
    redis:
      host: 192.168.200.128
      port: 6379
      database: 0

三、RedisConfig配置

package com.yuhuan.book.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;

@Configuration
public class RedisConfig {

    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        // 配置连接工厂
        redisTemplate.setConnectionFactory(factory);

        // 1. 配置 key 序列化器(必须是 String 格式,否则 Redis 中 key 会乱码)
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashKeySerializer(new StringRedisSerializer()); // hash 的 key 也用字符串序列化

        // 2. 配置 value 序列化器(JSON 格式,支持对象自动序列化/反序列化)
        GenericJackson2JsonRedisSerializer valueSerializer = new GenericJackson2JsonRedisSerializer();
        redisTemplate.setValueSerializer(valueSerializer);
        redisTemplate.setHashValueSerializer(valueSerializer); // hash 的 value 也用 JSON 序列化

        // 初始化 RedisTemplate
        redisTemplate.afterPropertiesSet();
        return redisTemplate;
    }
}

四、相关的方法

根据Redis的数据类型,RedisTemplate对各种交互方法做了分组,以下是常用的几个分组

分组说明
​redisTemplate.opsForValue()​操作string类型的方法
​redisTemplate.opsForList()​操作list类型的方法
​redisTemplate.opsForSet()​操作set类型的方法
​redisTemplate.opsForHash()​操作hash类型的方法
​redisTemplate.opsForZSet()​操作zset类型的方法
​redisTemplate​通用方法

五、使用示例

package com.yuhuan.book;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.connection.DataType;
import org.springframework.data.redis.core.*;

import java.util.*;
import java.util.concurrent.TimeUnit;

@SpringBootTest
public class RedisTemplateTest {

    // 注入 RedisTemplate(后续手动设置序列化器避免乱码)
    @Autowired
    private RedisTemplate redisTemplate;
    // ========================== 1. 字符串(String)操作(原有基础扩展)==========================
    @Test
    public void testStringOps() {
        ValueOperations valueOps = redisTemplate.opsForValue();

        // 1. 普通设值(无过期时间)
        valueOps.set("user002", "wangdaniu");
        // 2. 设值并设置过期时间(10分钟)
        valueOps.set("verify_code_138", "67890", 10, TimeUnit.MINUTES);
        // 3. 不存在时才设值(避免覆盖,返回 boolean)
        boolean success = valueOps.setIfAbsent("lock_key", "locked", 30, TimeUnit.SECONDS);
        System.out.println("锁设置成功?" + success);
        // 4. 取值
        String user = (String) valueOps.get("user002");
        String code = (String) valueOps.get("verify_code_138");
        System.out.println("user002: " + user);
        System.out.println("验证码: " + code);
        // 5. 自增(常用于计数器,比如文章阅读量)
        valueOps.set("article_view_1001", 0);
        Long viewCount = valueOps.increment("article_view_1001"); // 自增1,返回新值
        System.out.println("文章1001阅读量: " + viewCount);
        // 6. 自减(比如库存)
        valueOps.set("product_stock_2001", 100);
        Long stock = valueOps.decrement("product_stock_2001", 5); // 自减5,返回新值
        System.out.println("商品2001库存: " + stock);
    }

    // ========================== 2. 哈希(Hash)操作(适合存储对象属性)==========================
    @Test
    public void testHashOps() {
        HashOperations hashOps = redisTemplate.opsForHash();
        String hashKey = "user:1001"; // 哈希表的 key(比如用户ID)

        // 1. 单个属性设值
        hashOps.put(hashKey, "id", "1001");
        hashOps.put(hashKey, "username", "zhangsan");
        hashOps.put(hashKey, "age", "25");
        hashOps.put(hashKey, "email", "zhangsan@xxx.com");

        // 2. 批量设值(Map)
        Map<String, String> userMap = new HashMap<>();
        userMap.put("gender", "male");
        userMap.put("phone", "13800138000");
        hashOps.putAll(hashKey, userMap);

        // 3. 取值(单个属性)
        String username = (String) hashOps.get(hashKey, "username");
        System.out.println("用户名: " + username);

        // 4. 取所有属性和值(返回 Map)
        Map<String, String> allProperties = hashOps.entries(hashKey);
        System.out.println("用户1001所有属性: " + allProperties);

        // 5. 取所有属性名(key集合)
        Set<String> keys = hashOps.keys(hashKey);
        System.out.println("属性名集合: " + keys);

        // 6. 取所有属性值(value集合)
        List<String> values = hashOps.values(hashKey);
        System.out.println("属性值集合: " + values);

        // 7. 判断属性是否存在
        boolean hasEmail = hashOps.hasKey(hashKey, "email");
        System.out.println("是否有email属性?" + hasEmail);

        // 8. 删除某个属性
        hashOps.delete(hashKey, "phone");
        System.out.println("删除phone后属性: " + hashOps.entries(hashKey));
    }

    // ========================== 3. 列表(List)操作(有序、可重复,适合队列/栈)==========================
    @Test
    public void testListOps() {
        ListOperations listOps = redisTemplate.opsForList();
        String listKey = "message_queue"; // 比如消息队列

        // 1. 从列表左侧添加元素(栈:先进后出)
        listOps.leftPush(listKey, "msg1: 订单创建");
        listOps.leftPush(listKey, "msg2: 订单支付");
        listOps.leftPush(listKey, "msg3: 订单发货");

        // 2. 从列表右侧添加元素(队列:先进先出)
        listOps.rightPush(listKey, "msg4: 订单完成");

        // 3. 取列表长度
        Long size = listOps.size(listKey);
        System.out.println("消息队列长度: " + size);

        // 4. 遍历列表(0=开始索引,-1=结束索引,即所有元素)
        List<String> allMsg = listOps.range(listKey, 0, -1);
        System.out.println("所有消息: " + allMsg);

        // 5. 从左侧弹出元素(移除并返回)
        String leftPopMsg = (String) listOps.leftPop(listKey);
        System.out.println("左侧弹出消息: " + leftPopMsg);

        // 6. 从右侧弹出元素
        String rightPopMsg = (String) listOps.rightPop(listKey);
        System.out.println("右侧弹出消息: " + rightPopMsg);

        // 7. 按索引取值(0=第一个,-1=最后一个)
        String indexMsg = (String) listOps.index(listKey, 0);
        System.out.println("第一个消息: " + indexMsg);

        // 8. 截取列表(保留索引0-1的元素,其余删除)
        listOps.trim(listKey, 0, 1);
        System.out.println("截取后消息: " + listOps.range(listKey, 0, -1));
    }

    // ========================== 4. 集合(Set)操作(无序、不可重复,适合去重/交集)==========================
    @Test
    public void testSetOps() {
        SetOperations setOps = redisTemplate.opsForSet();
        String setKey1 = "user:1001:follow"; // 用户1001关注的人
        String setKey2 = "user:1002:follow"; // 用户1002关注的人

        // 1. 添加元素(可多个)
        setOps.add(setKey1, "user2001", "user2002", "user2003", "user2004");
        setOps.add(setKey2, "user2002", "user2003", "user2005", "user2006");

        // 2. 取集合所有元素
        Set<String> follow1 = setOps.members(setKey1);
        Set<String> follow2 = setOps.members(setKey2);
        System.out.println("用户1001关注: " + follow1);
        System.out.println("用户1002关注: " + follow2);

        // 3. 取两个集合的交集(共同关注)
        Set<String> commonFollow = setOps.intersect(setKey1, setKey2);
        System.out.println("共同关注: " + commonFollow);

        // 4. 取两个集合的并集(所有关注)
        Set<String> allFollow = setOps.union(setKey1, setKey2);
        System.out.println("所有关注(去重): " + allFollow);

        // 5. 取差集(用户1001关注但1002没关注的)
        Set<String> diffFollow = setOps.difference(setKey1, setKey2);
        System.out.println("1001独有关注: " + diffFollow);

        // 6. 判断元素是否在集合中
        boolean isFollow = setOps.isMember(setKey1, "user2002");
        System.out.println("1001是否关注user2002?" + isFollow);

        // 7. 随机弹出一个元素
        String randomMember = (String) setOps.pop(setKey1);
        System.out.println("随机弹出关注: " + randomMember);

        // 8. 集合大小
        Long setSize = setOps.size(setKey1);
        System.out.println("1001关注数: " + setSize);
    }

    // ========================== 5. 有序集合(ZSet)操作(有序、不可重复,适合排序/排名)==========================
    @Test
    public void testZSetOps() {
        ZSetOperations zSetOps = redisTemplate.opsForZSet();
        String zSetKey = "rank:score"; // 分数排行榜

        // 1. 添加元素(value + score,score用于排序)
        zSetOps.add(zSetKey, "user1001", 95.5);
        zSetOps.add(zSetKey, "user1002", 88.0);
        zSetOps.add(zSetKey, "user1003", 92.3);
        zSetOps.add(zSetKey, "user1004", 98.0);

        // 2. 按分数升序排列(0=开始索引,-1=所有元素)
        Set<String> ascRank = zSetOps.range(zSetKey, 0, -1);
        System.out.println("分数升序排名: " + ascRank);

        // 3. 按分数降序排列(常用:排行榜从高到低)
        Set<String> descRank = zSetOps.reverseRange(zSetKey, 0, -1);
        System.out.println("分数降序排名: " + descRank);

        // 4. 取元素的分数
        Double score = zSetOps.score(zSetKey, "user1004");
        System.out.println("user1004分数: " + score);

        // 5. 取元素的排名(升序排名,从0开始)
        Long rank = zSetOps.rank(zSetKey, "user1003");
        System.out.println("user1003升序排名(第N名): " + (rank + 1)); // +1 转为人习惯的排名

        // 6. 分数区间查询(比如80-90分的用户)
        Set<String> scoreRange = zSetOps.rangeByScore(zSetKey, 80, 90);
        System.out.println("80-90分用户: " + scoreRange);

        // 7. 给元素加分(比如用户积分增加)
        Double newScore = zSetOps.incrementScore(zSetKey, "user1002", 5.0);
        System.out.println("user1002加分后分数: " + newScore);

        // 8. 有序集合大小
        Long zSetSize = zSetOps.size(zSetKey);
        System.out.println("排行榜人数: " + zSetSize);
    }

    // ========================== 6. 通用操作(key相关)==========================
    @Test
    public void testCommonOps() {

        // 1. 判断key是否存在
        boolean exists = redisTemplate.hasKey("user002");
        System.out.println("user002是否存在?" + exists);

        // 2. 设置key过期时间(30秒)
        redisTemplate.expire("user002", 30, TimeUnit.SECONDS);

        // 3. 查看key剩余过期时间(返回-1=永久,-2=已过期/不存在)
        Long expire = redisTemplate.getExpire("user002", TimeUnit.SECONDS);
        System.out.println("user002剩余过期时间(秒): " + expire);

        // 4. 移除key过期时间(转为永久)
        redisTemplate.persist("user002");

        // 5. 模糊查询key(慎用!生产环境大数据量会阻塞Redis)
        Set<String> keys = redisTemplate.keys("user*"); // 匹配所有以user开头的key
        System.out.println("模糊查询user开头的key: " + keys);

        // 6. 删除key(单个)
        redisTemplate.delete("user002");
        // 7. 批量删除key
        redisTemplate.delete(Arrays.asList("verify_code_138", "lock_key"));

        // 8. 查看key的类型
        DataType type = redisTemplate.type("rank:score");
        System.out.println("rank:score的类型: " + type); // ZSET
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值