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:有序带权重,适合排序和排行榜。
  • 缓存问题需通过穿透(缓存空值)、击穿(互斥锁)、雪崩(随机过期)等方案解决,保障系统稳定性。
目录
相关文章
存储 JSON Java
118 0
|
19天前
|
SQL Java 数据库连接
Spring Data JPA 技术深度解析与应用指南
本文档全面介绍 Spring Data JPA 的核心概念、技术原理和实际应用。作为 Spring 生态系统中数据访问层的关键组件,Spring Data JPA 极大简化了 Java 持久层开发。本文将深入探讨其架构设计、核心接口、查询派生机制、事务管理以及与 Spring 框架的集成方式,并通过实际示例展示如何高效地使用这一技术。本文档约1500字,适合有一定 Spring 和 JPA 基础的开发者阅读。
98 0
|
1月前
|
人工智能 监控 安全
如何快速上手【Spring AOP】?核心应用实战(上篇)
哈喽大家好吖~欢迎来到Spring AOP系列教程的上篇 - 应用篇。在本篇,我们将专注于Spring AOP的实际应用,通过具体的代码示例和场景分析,帮助大家掌握AOP的使用方法和技巧。而在后续的下篇中,我们将深入探讨Spring AOP的实现原理和底层机制。 AOP(Aspect-Oriented Programming,面向切面编程)是Spring框架中的核心特性之一,它能够帮助我们解决横切关注点(如日志记录、性能统计、安全控制、事务管理等)的问题,提高代码的模块化程度和复用性。
|
1月前
|
监控 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注册中心服务 构建商品
327 3
|
1月前
|
安全 算法 Java
在Spring Boot中应用Jasypt以加密配置信息。
通过以上步骤,可以在Spring Boot应用中有效地利用Jasypt对配置信息进行加密,这样即使配置文件被泄露,其中的敏感信息也不会直接暴露给攻击者。这是一种在不牺牲操作复杂度的情况下提升应用安全性的简便方法。
627 10
|
2月前
|
安全 Java Nacos
0代码改动实现Spring应用数据库帐密自动轮转
Nacos作为国内被广泛使用的配置中心,已经成为应用侧的基础设施产品,近年来安全问题被更多关注,这是中国国内软件行业逐渐迈向成熟的标志,也是必经之路,Nacos提供配置加密存储-运行时轮转的核心安全能力,将在应用安全领域承担更多职责。
|
2月前
|
存储 NoSQL 定位技术
Redis数据类型面试给分情况
Redis常见数据类型包括:string、hash、list、set、zset(有序集合)。此外还包含高级结构如bitmap、hyperloglog、geo。不同场景可选用合适类型,如库存用string,对象存hash,列表用list,去重场景用set,排行用zset,签到用bitmap,统计访问量用hyperloglog,地理位置用geo。
85 5
|
5天前
|
存储 缓存 NoSQL
Redis专题-实战篇二-商户查询缓存
本文介绍了缓存的基本概念、应用场景及实现方式,涵盖Redis缓存设计、缓存更新策略、缓存穿透问题及其解决方案。重点讲解了缓存空对象与布隆过滤器的使用,并通过代码示例演示了商铺查询的缓存优化实践。
57 1
Redis专题-实战篇二-商户查询缓存
|
5天前
|
缓存 NoSQL 关系型数据库
Redis缓存和分布式锁
Redis 是一种高性能的键值存储系统,广泛用于缓存、消息队列和内存数据库。其典型应用包括缓解关系型数据库压力,通过缓存热点数据提高查询效率,支持高并发访问。此外,Redis 还可用于实现分布式锁,解决分布式系统中的资源竞争问题。文章还探讨了缓存的更新策略、缓存穿透与雪崩的解决方案,以及 Redlock 算法等关键技术。