Redis基本数据类型及Spring Data Redis应用

简介: Redis 是开源高性能键值对数据库,支持 String、Hash、List、Set、Sorted Set 等数据结构,适用于缓存、消息队列、排行榜等场景。具备高性能、原子操作及丰富功能,是分布式系统核心组件。

一、Redis 概述

  • 定义:Redis(Remote Dictionary Server)是开源的高性能键值对存储数据库,以内存为主要存储介质。
  • 核心特点
  • 高性能:单线程模型 + IO 多路复用,支持每秒数十万次操作;
  • 多数据结构:原生支持 String、Hash、List、Set、Sorted Set(ZSet)5 种基本类型,及 Bitmap 等扩展类型;
  • 原子操作:所有命令原子性,支持事务和 Lua 脚本;
  • 丰富功能:过期时间、发布订阅、分布式锁、地理空间等。
  • 应用场景:缓存、会话存储、消息队列、排行榜等,是分布式系统核心组件。

二、Redis 官方资源

三、Spring Data Redis 依赖(Maven)

<!-- Spring Data Redis 核心依赖 -->
<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>

四、Redis 5 种基本类型详解

1. String(字符串)

  • 数据结构:二进制安全,可存储文本、数字、二进制数据(最大 512MB),底层基于简单动态字符串(SDS)。
  • 应用场景:缓存简单数据(如用户信息 JSON)、计数器(文章阅读量)、分布式锁、限流等。
  • 原生命令示例


命令 说明 例子 执行后结果
SET key value [EX seconds] 设置键值对(可选过期时间) SET article:1001 "Redis 教程" EX 3600 article:1001 → "Redis 教程"(1 小时过期)
GET key 获取键值 GET article:1001 返回 "Redis 教程"
INCR key 数值自增 1(原子操作) INCR view:1001 从 0→1
DECR key 数值自减 1 DECR stock:phone 从 10→9
GETSET key value 先获取旧值,再设新值 GETSET counter:1 0 返回旧值 5,设为 0


  • Spring Data Redis 实现
@Component
public class StringDemo {
    @Resource
    private StringRedisTemplate stringRedisTemplate;
    // 缓存用户信息(带过期时间)
    public void cacheUserInfo(String userId, String userJson, int expireSeconds) {
        stringRedisTemplate.opsForValue().set("user:" + userId, userJson, expireSeconds, TimeUnit.SECONDS);
        // 结果:user:100 → "{\"name\":\"张三\"}"(3600秒后过期)
    }
    // 文章阅读量自增
    public Long incrementArticleView(String articleId) {
        return stringRedisTemplate.opsForValue().increment("view:" + articleId); // 结果:原数值+1
    }
    // 获取缓存的用户信息
    public String getUserInfo(String userId) {
        return stringRedisTemplate.opsForValue().get("user:" + userId); // 结果:如"{\"name\":\"张三\"}"
    }
}

2. Hash(哈希)

  • 数据结构:类似 HashMap,由 field-value 键值对组成,适合存储对象。小数据用压缩列表(ziplist),大数据用哈希表(hashtable)。
  • 应用场景:存储对象型数据(用户信息、商品详情),支持字段级操作(避免全量序列化)。
  • 原生命令示例
命令 说明 例子 执行后结果
HSET key field value 设置哈希字段值 HSET user:100 name "张三" age "25" user:100 → {name: "张三", age: "25"}
HGET key field 获取哈希字段值 HGET user:100 name 返回 "张三"
HMGET key field1 field2 批量获取字段值 HMGET user:100 name age 返回 ["张三", "25"]
HGETALL key 获取所有字段和值 HGETALL user:100 返回 ["name", "张三", "age", "25"]
HDEL key field 删除哈希字段 HDEL user:100 age 剩余 {name: "张三"}


  • Spring Data Redis 实现
@Component
public class HashDemo {
    @Resource
    private StringRedisTemplate stringRedisTemplate;
    // 存储用户信息(多字段)
    public void saveUser(String userId) {
        HashOperations<String, String, String> hashOps = stringRedisTemplate.opsForHash();
        Map<String, String> userMap = new HashMap<>();
        userMap.put("name", "张三");
        userMap.put("age", "25");
        hashOps.putAll("user:" + userId, userMap);
        // 结果:user:100 → {name: "张三", age: "25"}
    }
    // 获取用户姓名
    public String getUserName(String userId) {
        return stringRedisTemplate.opsForHash().get("user:" + userId, "name"); // 返回"张三"
    }
    // 获取用户所有信息
    public Map<String, String> getUserAll(String userId) {
        return stringRedisTemplate.opsForHash().entries("user:" + userId); // 返回所有字段和值
    }
}

3. List(列表)

  • 数据结构:有序可重复元素集合,类似双向链表,支持两端插入 / 删除。小数据用压缩列表(ziplist),大数据用双向链表(linkedlist)。
  • 应用场景:消息队列(LPUSH+RPOP)、最新列表(如最新文章)、有限长度排行榜。
  • 原生命令示例
命令 说明 例子 执行后结果
LPUSH key value1 [value2] 左侧插入元素 LPUSH msg:queue "消息 1" "消息 2" msg:queue → ["消息 2", "消息 1"]
RPUSH key value1 [value2] 右侧插入元素 RPUSH article:new "ID1" "ID2" article:new → ["ID1", "ID2"]
LPOP key 左侧弹出元素 LPOP msg:queue 返回 "消息 2",剩余 ["消息 1"]
RPOP key 右侧弹出元素 RPOP article:new 返回 "ID2",剩余 ["ID1"]
LRANGE key start end 获取范围元素 LRANGE article:new 0 1 若列表为 ["ID1","ID2","ID3"],返回 ["ID1","ID2"]


  • Spring Data Redis 实现
@Component
public class ListDemo {
    @Resource
    private StringRedisTemplate stringRedisTemplate;
    // 发送消息(左侧插入,模拟队列)
    public Long sendMessage(String queueName, String message) {
        Long newSize = stringRedisTemplate.opsForList().leftPush(queueName, message);
        // 结果:msg:queue → [新消息, 原元素...]
        return newSize;
    }
    // 消费消息(右侧弹出)
    public String consumeMessage(String queueName) {
        return stringRedisTemplate.opsForList().rightPop(queueName); // 返回弹出的消息
    }
    // 获取最新5条文章ID
    public List<String> getLatestArticles(String listKey) {
        return stringRedisTemplate.opsForList().range(listKey, 0, 4); // 返回前5条
    }
}

4. Set(集合)

  • 数据结构:无序、不可重复元素集合,支持交集、并集、差集。小数据用压缩列表(ziplist),大数据用哈希表(hashtable)。
  • 应用场景:去重存储(用户标签)、共同好友计算、随机抽奖等。
  • 原生命令示例
命令 说明 例子 执行后结果
SADD key member1 [member2] 添加元素(自动去重) SADD user:100:tags "足球" "音乐" "足球" user:100:tags → {"足球", "音乐"}
SMEMBERS key 获取所有元素 SMEMBERS user:100:tags 返回 ["足球", "音乐"](顺序随机)
SINTER key1 key2 计算交集 SINTER user:100:tags user:200:tags(user200 含 {"音乐","阅读"}) 返回 ["音乐"]
SUNION key1 key2 计算并集 SUNION user:100:tags user:200:tags 返回 ["足球", "音乐", "阅读"]
SREM key member 移除元素 SREM user:100:tags "音乐" 剩余 {"足球"}


  • Spring Data Redis 实现
@Component
public class SetDemo {
    @Resource
    private StringRedisTemplate stringRedisTemplate;
    // 给用户添加标签(自动去重)
    public Long addUserTags(String userId, String... tags) {
        return stringRedisTemplate.opsForSet().add("user:" + userId + ":tags", tags);
    }
    // 获取用户所有标签
    public Set<String> getUserTags(String userId) {
        return stringRedisTemplate.opsForSet().members("user:" + userId + ":tags");
    }
    // 计算两个用户的共同标签(交集)
    public Set<String> getCommonTags(String userId1, String userId2) {
        return stringRedisTemplate.opsForSet().intersect(
            "user:" + userId1 + ":tags", 
            "user:" + userId2 + ":tags"
        );
    }
}

5. Sorted Set(ZSet,有序集合)

  • 数据结构:元素关联 score(分数),按分数排序(分数可重复,元素不可重复)。小数据用压缩列表(ziplist),大数据用跳表(skiplist)+ 哈希表。
  • 应用场景:游戏排行榜(按分数排序)、延迟队列(按时间戳为 score)、TOP N 统计。
  • 原生命令示例


命令 说明 例子 执行后结果
ZADD key score member 添加元素及分数 ZADD game:rank 95 "用户 A" 88 "用户 B" 按 score 升序存储:{("用户 B",88), ("用户 A",95)}
ZREVRANGE key start end [WITHSCORES] 按 score 降序取元素 ZREVRANGE game:rank 0 1 WITHSCORES 返回 ["用户 A", "95", "用户 B", "88"]
ZSCORE key member 获取元素分数 ZSCORE game:rank "用户 A" 返回 "95"
ZINCRBY key increment member 增加元素分数 ZINCRBY game:rank 5 "用户 B" 用户 B 分数从 88→93


  • Spring Data Redis 实现
@Component
public class ZSetDemo {
    @Resource
    private StringRedisTemplate stringRedisTemplate;
    // 添加用户到排行榜(初始分数)
    public Boolean addToRank(String userName, double score) {
        return stringRedisTemplate.opsForZSet().add("game:rank", userName, score);
    }
    // 增加用户分数
    public Double incrementScore(String userName, double increment) {
        return stringRedisTemplate.opsForZSet().incrementScore("game:rank", userName, increment);
    }
    // 获取排行榜前三名(降序,带分数)
    public Set<ZSetOperations.TypedTuple<String>> getTop3() {
        return stringRedisTemplate.opsForZSet().reverseRangeWithScores("game:rank", 0, 2);
    }
}

五、缓存问题解决方案(穿透、击穿、雪崩)

在使用 Redis 缓存时,需注意解决以下常见问题,避免对数据库或系统造成压力:

1. 缓存穿透

  • 问题描述:查询不存在的数据(如 ID 为 -1 的用户),导致请求绕过缓存直接访问数据库,大量请求可能压垮数据库。
  • 解决方案:缓存空值(设置较短过期时间)+ 布隆过滤器(提前拦截不存在的 key)。
  • Spring Data Redis 实现示例(缓存空值)
@Component
public class CachePenetrationDemo {
    @Resource
    private StringRedisTemplate stringRedisTemplate;
    @Resource
    private UserDao userDao; // 假设存在用户DAO层
    // 查询用户信息,解决缓存穿透
    public String getUserById(String userId) {
        String key = "user:" + userId;
        String userJson = stringRedisTemplate.opsForValue().get(key);
        // 缓存命中(包括空值)
        if (userJson != null) {
            // 返回空值标记时,实际返回null
            return "NULL".equals(userJson) ? null : userJson;
        }
        // 缓存未命中,查询数据库
        User user = userDao.selectById(userId);
        if (user == null) {
            // 缓存空值,设置短过期时间(如5分钟),避免缓存穿透
            stringRedisTemplate.opsForValue().set(key, "NULL", 300, TimeUnit.SECONDS);
            return null;
        }
        // 数据库存在,缓存用户信息(正常过期时间,如1小时)
        userJson = JSON.toJSONString(user); // 假设使用FastJSON
        stringRedisTemplate.opsForValue().set(key, userJson, 3600, TimeUnit.SECONDS);
        return userJson;
    }
}

2. 缓存击穿

  • 问题描述:热点 key 过期瞬间,大量请求同时访问,击穿缓存直接访问数据库,导致数据库压力骤增。
  • 解决方案:互斥锁(同一时间只允许一个请求更新缓存)+ 热点 key 永不过期。
  • Spring Data Redis 实现示例(基于分布式锁)
@Component
public class CacheBreakdownDemo {
    @Resource
    private StringRedisTemplate stringRedisTemplate;
    @Resource
    private ProductDao productDao; // 假设存在商品DAO层
    // 查询商品详情,解决缓存击穿
    public String getProductById(String productId) {
        String key = "product:" + productId;
        String productJson = stringRedisTemplate.opsForValue().get(key);
        // 缓存命中,直接返回
        if (productJson != null) {
            return productJson;
        }
        // 缓存未命中,尝试获取分布式锁
        String lockKey = "lock:product:" + productId;
        try {
            // 使用setIfAbsent实现简单分布式锁,过期时间10秒(避免死锁)
            Boolean locked = stringRedisTemplate.opsForValue().setIfAbsent(lockKey, "1", 10, TimeUnit.SECONDS);
            if (Boolean.TRUE.equals(locked)) {
                // 获取锁成功,查询数据库并更新缓存
                Product product = productDao.selectById(productId);
                if (product == null) {
                    // 缓存空值(同穿透处理)
                    stringRedisTemplate.opsForValue().set(key, "NULL", 300, TimeUnit.SECONDS);
                    return null;
                }
                // 缓存商品信息(正常过期时间)
                productJson = JSON.toJSONString(product);
                stringRedisTemplate.opsForValue().set(key, productJson, 3600, TimeUnit.SECONDS);
                return productJson;
            } else {
                // 获取锁失败,休眠后重试(如50ms)
                Thread.sleep(50);
                return getProductById(productId); // 递归重试
            }
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        } finally {
            // 释放锁(仅持有锁的线程可释放)
            stringRedisTemplate.delete(lockKey);
        }
    }
}

3. 缓存雪崩

  • 问题描述:大量缓存 key 同时过期,或 Redis 服务宕机,导致请求瞬间全部压向数据库,引发数据库崩溃。
  • 解决方案:过期时间随机化(避免集中过期)+ 缓存集群(高可用)+ 服务熔断降级。
  • Spring Data Redis 实现示例(过期时间随机化)
@Component
public class CacheAvalancheDemo {
    @Resource
    private StringRedisTemplate stringRedisTemplate;
    // 缓存数据时添加随机过期时间,解决缓存雪崩
    public void cacheDataWithRandomExpire(String key, String value) {
        // 基础过期时间(如1小时)+ 随机时间(0-30分钟),避免大量key同时过期
        int baseExpire = 3600;
        int randomExpire = new Random().nextInt(1800); // 0-1800秒
        stringRedisTemplate.opsForValue().set(key, value, baseExpire + randomExpire, TimeUnit.SECONDS);
    }
}

六、总结

  • String:简单键值对,适合缓存和计数;
  • Hash:对象存储,支持字段级操作;
  • List:有序可重复,适合队列和最新列表;
  • Set:无序去重,适合交集计算和去重;
  • ZSet:有序带权重,适合排序和排行榜。
  • 缓存问题需通过穿透(缓存空值)、击穿(互斥锁)、雪崩(随机过期)等方案解决,保障系统稳定性。
Adrian_
+关注
目录
打赏
0
2
2
0
6
分享
相关文章
|
7天前
|
在Spring Boot中应用Jasypt以加密配置信息。
通过以上步骤,可以在Spring Boot应用中有效地利用Jasypt对配置信息进行加密,这样即使配置文件被泄露,其中的敏感信息也不会直接暴露给攻击者。这是一种在不牺牲操作复杂度的情况下提升应用安全性的简便方法。
98 0
0代码改动实现Spring应用数据库帐密自动轮转
Nacos作为国内被广泛使用的配置中心,已经成为应用侧的基础设施产品,近年来安全问题被更多关注,这是中国国内软件行业逐渐迈向成熟的标志,也是必经之路,Nacos提供配置加密存储-运行时轮转的核心安全能力,将在应用安全领域承担更多职责。
Redis数据类型面试给分情况
Redis常见数据类型包括:string、hash、list、set、zset(有序集合)。此外还包含高级结构如bitmap、hyperloglog、geo。不同场景可选用合适类型,如库存用string,对象存hash,列表用list,去重场景用set,排行用zset,签到用bitmap,统计访问量用hyperloglog,地理位置用geo。
43 5
Linux云端服务器上部署Spring Boot应用的教程。
此流程涉及Linux命令行操作、系统服务管理及网络安全知识,需要管理员权限以进行配置和服务管理。务必在一个测试环境中验证所有步骤,确保一切配置正确无误后,再将应用部署到生产环境中。也可以使用如Ansible、Chef等配置管理工具来自动化部署过程,提升效率和可靠性。
142 13
【Azure Redis】Redis服务端的故障转移(Failover)导致客户端应用出现15分钟超时问题的模拟及解决
在使用 Azure Cache for Redis 服务时,因服务端维护可能触发故障转移。Linux 环境下使用 Lettuce SDK 会遇到超时 15 分钟的已知问题。本文介绍如何通过重启 Primary 节点主动复现故障转移,并提供多种解决方案,包括调整 TCP 设置、升级 Lettuce 版本、配置 TCP_USER_TIMEOUT 及使用其他 SDK(如 Jedis)来规避此问题。
Spring Boot 框架超级详细总结及长尾关键词应用解析
本文深入讲解Spring Boot框架的核心概念、功能特性及实际应用,涵盖自动配置、独立运行、starter依赖等优势。通过Web开发、微服务架构、批处理等适用场景分析,结合在线书店实战案例,演示项目初始化、数据库设计、分层架构实现全流程。同时探讨热部署、多环境配置、缓存机制与事务管理等高级特性,助你高效掌握Spring Boot开发技巧。代码示例详尽,适合从入门到进阶的学习者。
408 0
|
3月前
|
Redis+Caffeine构建高性能二级缓存
大家好,我是摘星。今天为大家带来的是Redis+Caffeine构建高性能二级缓存,废话不多说直接开始~
449 0
基于Spring Data Redis与RabbitMQ实现字符串缓存和计数功能(数据同步)
总的来说,借助Spring Data Redis和RabbitMQ,我们可以轻松实现字符串缓存和计数的功能。而关键的部分不过是一些"厨房的套路",一旦你掌握了这些套路,那么你就像厨师一样可以准备出一道道饕餮美食了。通过这种方式促进数据处理效率无疑将大大提高我们的生产力。
143 32
|
3月前
|
Redis:现代服务端开发的缓存基石与电商实践-优雅草卓伊凡
Redis:现代服务端开发的缓存基石与电商实践-优雅草卓伊凡
84 5
Redis:现代服务端开发的缓存基石与电商实践-优雅草卓伊凡
AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等

登录插画

登录以查看您的控制台资源

管理云资源
状态一览
快捷访问