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:有序带权重,适合排序和排行榜。
  • 缓存问题需通过穿透(缓存空值)、击穿(互斥锁)、雪崩(随机过期)等方案解决,保障系统稳定性。
目录
相关文章
|
1月前
|
NoSQL Java 数据库连接
《深入理解Spring》Spring Data——数据访问的统一抽象与极致简化
Spring Data通过Repository抽象和方法名派生查询,简化数据访问层开发,告别冗余CRUD代码。支持JPA、MongoDB、Redis等多种存储,统一编程模型,提升开发效率与架构灵活性,是Java开发者必备利器。(238字)
|
1月前
|
存储 Java 关系型数据库
Spring Boot中Spring Data JPA的常用注解
Spring Data JPA通过注解简化数据库操作,实现实体与表的映射。常用注解包括:`@Entity`、`@Table`定义表结构;`@Id`、`@GeneratedValue`配置主键策略;`@Column`、`@Transient`控制字段映射;`@OneToOne`、`@OneToMany`等处理关联关系;`@Enumerated`、`@NamedQuery`支持枚举与命名查询。合理使用可提升开发效率与代码可维护性。(238字)
286 1
|
1月前
|
消息中间件 缓存 Java
Spring框架优化:提高Java应用的性能与适应性
以上方法均旨在综合考虑Java Spring 应该程序设计原则, 数据库交互, 编码实践和系统架构布局等多角度因素, 旨在达到高效稳定运转目标同时也易于未来扩展.
121 8
存储 JSON Java
471 0
|
2月前
|
NoSQL Java 调度
分布式锁与分布式锁使用 Redis 和 Spring Boot 进行调度锁(不带 ShedLock)
分布式锁是分布式系统中用于同步多节点访问共享资源的机制,防止并发操作带来的冲突。本文介绍了基于Spring Boot和Redis实现分布式锁的技术方案,涵盖锁的获取与释放、Redis配置、服务调度及多实例运行等内容,通过Docker Compose搭建环境,验证了锁的有效性与互斥特性。
205 0
分布式锁与分布式锁使用 Redis 和 Spring Boot 进行调度锁(不带 ShedLock)
|
2月前
|
SQL Java 数据库连接
Spring Data JPA 技术深度解析与应用指南
本文档全面介绍 Spring Data JPA 的核心概念、技术原理和实际应用。作为 Spring 生态系统中数据访问层的关键组件,Spring Data JPA 极大简化了 Java 持久层开发。本文将深入探讨其架构设计、核心接口、查询派生机制、事务管理以及与 Spring 框架的集成方式,并通过实际示例展示如何高效地使用这一技术。本文档约1500字,适合有一定 Spring 和 JPA 基础的开发者阅读。
320 0
|
3月前
|
Java 应用服务中间件 开发者
Spring Boot 技术详解与应用实践
本文档旨在全面介绍 Spring Boot 这一广泛应用于现代企业级应用开发的框架。内容将涵盖 Spring Boot 的核心概念、核心特性、项目自动生成与结构解析、基础功能实现(如 RESTful API、数据访问)、配置管理以及最终的构建与部署。通过本文档,读者将能够理解 Spring Boot 如何简化 Spring 应用的初始搭建和开发过程,并掌握其基本使用方法。
335 2
|
3月前
|
人工智能 监控 安全
如何快速上手【Spring AOP】?核心应用实战(上篇)
哈喽大家好吖~欢迎来到Spring AOP系列教程的上篇 - 应用篇。在本篇,我们将专注于Spring AOP的实际应用,通过具体的代码示例和场景分析,帮助大家掌握AOP的使用方法和技巧。而在后续的下篇中,我们将深入探讨Spring AOP的实现原理和底层机制。 AOP(Aspect-Oriented Programming,面向切面编程)是Spring框架中的核心特性之一,它能够帮助我们解决横切关注点(如日志记录、性能统计、安全控制、事务管理等)的问题,提高代码的模块化程度和复用性。
|
3月前
|
监控 Java API
Spring Boot 3.2 结合 Spring Cloud 微服务架构实操指南 现代分布式应用系统构建实战教程
Spring Boot 3.2 + Spring Cloud 2023.0 微服务架构实践摘要 本文基于Spring Boot 3.2.5和Spring Cloud 2023.0.1最新稳定版本,演示现代微服务架构的构建过程。主要内容包括: 技术栈选择:采用Spring Cloud Netflix Eureka 4.1.0作为服务注册中心,Resilience4j 2.1.0替代Hystrix实现熔断机制,配合OpenFeign和Gateway等组件。 核心实操步骤: 搭建Eureka注册中心服务 构建商品
674 3
|
NoSQL Java 数据库

热门文章

最新文章

下一篇
oss云网关配置