13 Redis 数据库与 Spring Boot

发布时间:2026/8/3 2:41:18
13 Redis 数据库与 Spring Boot 第一章.NoSQL 数据库1.1 什么是 NoSQL1.NoSQL: Not Only SQL,泛指非关系型数据库。 2.关系型数据库: 使用表、行、列保存数据,依赖 SQL 操作。 例如 MySQL、Oracle、PostgreSQL。 3.NoSQL 数据库: 不强制使用固定表结构,通常更适合高并发、大数据量、灵活结构的数据场景。1.2 NoSQL 适用场景场景说明高并发读写秒杀、热点数据、接口缓存海量数据数据量大关系模型不强灵活数据结构字段变化频繁不适合固定表结构临时状态数据token、验证码、购物车、排行榜Redis 常见用途: 1.缓存热点数据。 2.保存登录 token。 3.保存验证码。 4.实现分布式锁。 5.实现排行榜。 6.实现计数器。1.3 NoSQL 不适用场景1.需要复杂事务: 例如银行核心账务。 2.需要复杂关联查询: 多表 join、复杂报表统计。 3.需要强关系模型: 数据之间约束关系非常复杂。 4.要求 SQL 标准能力: 使用关系型数据库更合适。1.4 常见 NoSQL 数据库数据库类型特点RedisKey-Value内存数据库速度快支持多种数据结构MemcachedKey-Value简单缓存数据结构较少MongoDB文档型类 JSON 文档存储结构灵活Elasticsearch搜索引擎全文检索、日志分析第二章.Redis 简介和安装2.1 Redis 的介绍1.Redis: Remote Dictionary Server,远程字典服务。 2.本质: 基于内存的 Key-Value 数据库。 3.特点: a.读写速度快 b.支持丰富数据类型 c.支持持久化 d.支持主从复制、哨兵、集群 e.常用于缓存和高并发场景2.2 Redis 和 MySQL 的关系客户端请求 ↓ 后端服务 ↓ 先查 Redis 缓存 ↓ 缓存没有再查 MySQL 数据库1.MySQL: 负责长期、可靠地保存核心业务数据。 2.Redis: 负责保存热点数据,提高访问速度。 3.常见策略: 先查 Redis。 Redis 没有再查 MySQL。 查到后写入 Redis。2.3 Linux 安装 Redis 常见步骤# 解压 tar -zxvf redis-7.0.0.tar.gz # 进入目录 cd redis-7.0.0 # 编译 make # 安装 make install1.Redis 通常通过源码编译安装。 2.安装后常见命令包括 redis-server 和 redis-cli。 3.真实版本号以本机下载的 Redis 版本为准。2.4 Redis 启动和停止前台启动redis-server前台启动: 1.当前命令窗口不能关闭。 2.适合临时测试。后台启动修改redis.conf:daemonize yes启动:redis-server redis.conf客户端连接redis-cli指定主机和端口:redis-cli -h 127.0.0.1 -p 6379停止服务redis-cli shutdown2.5 基础连接测试127.0.0.1:6379 ping PONG看到 PONG 表示 Redis 服务正常响应。第三章.Redis key 操作3.1 key 的特点1.Redis 中所有数据都通过 key 访问。 2.key 是字符串。 3.key 应该有清晰命名规则。命名建议:业务名:对象名:id:字段示例:user:1001:name login:token:1001 product:hot:list3.2 key 常用命令命令说明keys pattern按模式查询 keyexists key判断 key 是否存在type key查看 key 对应 value 类型del key删除 keyexpire key seconds设置过期时间ttl key查看剩余过期时间rename old new重命名 keydbsize查看当前库 key 数量flushdb清空当前库flushall清空所有库set user:1:name tom exists user:1:name type user:1:name expire user:1:name 60 ttl user:1:name del user:1:name生产环境慎用 keys 和 flushkeys *会扫描所有 key数据量大时可能阻塞 Redisflushdb和flushall会清空数据生产环境必须谨慎。第四章.String 字符串4.1 String 的介绍1.String: Redis 最基础的数据类型。 2.value 可以是: 字符串 数字 JSON 字符串 二进制数据 3.常见用途: 缓存对象 JSON 计数器 验证码 token4.2 常用命令命令说明set key value设置字符串get key获取字符串setex key seconds value设置值并指定过期时间setnx key valuekey 不存在时才设置mset k1 v1 k2 v2批量设置mget k1 k2批量获取incr key数值加 1decr key数值减 1incrby key n数值增加 nappend key value追加字符串strlen key获取字符串长度4.3 案例:验证码setex code:login:13800000000 300 9527 get code:login:13800000000 ttl code:login:138000000001.验证码通常有过期时间。 2.setex 可以一次完成写入和设置过期时间。 3.key 中加入手机号可以区分不同用户。4.4 案例:计数器set article:1001:read 0 incr article:1001:read incrby article:1001:read 10 get article:1001:read第五章.List 列表5.1 List 的介绍1.List: Redis 列表,底层可以理解为双端队列。 2.特点: a.元素有序 b.元素可重复 c.可以从左侧或右侧插入、弹出 3.常见用途: 消息队列 最新列表 栈或队列5.2 常用命令命令说明lpush key value...从左侧插入rpush key value...从右侧插入lpop key从左侧弹出rpop key从右侧弹出lrange key start stop按范围查看llen key查看长度lindex key index按索引取值lrem key count value删除指定元素5.3 队列案例rpush task:queue task1 task2 task3 lpop task:queue lpop task:queue lrange task:queue 0 -1rpush lpop: 先进先出,可以模拟队列。5.4 栈案例lpush stack:a a lpush stack:a b lpush stack:a c lpop stack:alpush lpop: 后进先出,可以模拟栈。第六章.Set 集合6.1 Set 的介绍1.Set: Redis 无序集合。 2.特点: a.元素无序 b.元素不可重复 c.支持交集、并集、差集 3.常见用途: 去重 共同好友 用户标签 抽奖6.2 常用命令命令说明sadd key member...添加元素smembers key查看全部元素sismember key member判断元素是否存在srem key member...删除元素scard key获取元素数量srandmember key count随机获取元素spop key count随机弹出元素sinter key1 key2交集sunion key1 key2并集sdiff key1 key2差集6.3 案例:共同好友sadd user:1:follows 2 3 4 5 sadd user:2:follows 3 4 6 sinter user:1:follows user:2:followssinter 可以求两个集合的交集。 共同关注、共同好友都可以用类似思路。6.4 案例:抽奖sadd lottery:user 1001 1002 1003 1004 srandmember lottery:user 2 spop lottery:user 11.srandmember: 随机取,不删除。 2.spop: 随机取,并删除。第七章.Hash 哈希7.1 Hash 的介绍1.Hash: key 对应一个 field-value 结构。 2.适合存储: 对象数据。 3.示例: user:1001 nametom age18 phone138000000007.2 常用命令命令说明hset key field value设置字段hget key field获取字段hmset key f1 v1 f2 v2批量设置hmget key f1 f2批量获取hgetall key获取全部字段和值hdel key field...删除字段hexists key field判断字段是否存在hkeys key获取全部 fieldhvals key获取全部 valuehincrby key field n字段数值增加7.3 案例:保存用户对象hset user:1001 name tom hset user:1001 age 18 hset user:1001 phone 13800000000 hget user:1001 name hgetall user:1001Hash 比 String 存 JSON 更方便局部修改字段。 如果业务经常整体读取对象,String 存 JSON 也很常见。第八章.ZSet 有序集合8.1 ZSet 的介绍1.ZSet: Sorted Set,有序集合。 2.特点: a.元素不可重复 b.每个元素有一个 score 分数 c.按照 score 排序 3.常见用途: 排行榜 热搜榜 延迟队列8.2 常用命令命令说明zadd key score member添加元素和分数zrange key start stop从小到大按排名查看zrevrange key start stop从大到小按排名查看zrangebyscore key min max按分数范围查询zrank key member获取从小到大排名zrevrank key member获取从大到小排名zscore key member获取分数zincrby key increment member增加分数zrem key member删除元素8.3 案例:文章排行榜zadd article:rank 100 article:1 zadd article:rank 80 article:2 zadd article:rank 120 article:3 zrevrange article:rank 0 2 withscores zincrby article:rank 30 article:2 zrevrank article:rank article:2zrevrange: 按分数从高到低查询,很适合排行榜。第九章.Redis 综合练习9.1 用户登录 tokensetex login:token:abc123 1800 user:1001 get login:token:abc123 ttl login:token:abc1231.登录成功后生成 token。 2.token 作为 key,用户 id 作为 value。 3.设置过期时间,到期自动失效。9.2 商品详情缓存setex product:1001 3600 {id:1001,name:Java课程,price:99} get product:1001缓存流程: 1.先查 Redis。 2.Redis 有数据直接返回。 3.Redis 没有查 MySQL。 4.查到后写入 Redis 并设置过期时间。9.3 秒杀库存扣减set seckill:stock:1001 100 decr seckill:stock:1001 get seckill:stock:1001decr 是 Redis 原子命令。 但完整秒杀还需要处理库存不能小于 0、重复下单、订单异步创建等问题。第十章.Jedis 客户端10.1 Jedis 的介绍1.Jedis: Java 操作 Redis 的客户端工具。 2.特点: API 和 Redis 命令名称接近。 3.使用场景: 学习 Redis Java API。 简单项目直接访问 Redis。10.2 Maven 依赖dependency groupIdredis.clients/groupId artifactIdjedis/artifactId version5.1.0/version /dependency10.3 基本使用import redis.clients.jedis.Jedis; public class JedisDemo { public static void main(String[] args) { try (Jedis jedis new Jedis(127.0.0.1, 6379)) { String pong jedis.ping(); System.out.println(pong); jedis.set(name, tom); String name jedis.get(name); System.out.println(name); } } }10.4 操作常见数据类型try (Jedis jedis new Jedis(127.0.0.1, 6379)) { jedis.set(user:1:name, tom); jedis.lpush(list:demo, a, b, c); jedis.sadd(set:demo, java, redis, java); jedis.hset(user:1, age, 18); jedis.zadd(rank, 100, user:1); }第十一章.Spring Boot 整合 Redis11.1 Spring Data Redis1.Spring Data Redis: Spring 提供的 Redis 操作封装。 2.常用核心对象: RedisTemplate StringRedisTemplate 3.好处: 和 Spring Boot 自动配置、连接池、序列化机制整合更方便。11.2 添加依赖dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-data-redis/artifactId /dependency dependency groupIdorg.apache.commons/groupId artifactIdcommons-pool2/artifactId /dependency11.3 application.yml 配置spring: data: redis: host: 127.0.0.1 port: 6379 database: 0 timeout: 3000ms lettuce: pool: enabled: true max-active: 8 max-idle: 8 min-idle: 0 max-wait: 1000ms1.host: Redis 服务器地址。 2.port: Redis 端口,默认 6379。 3.database: 使用第几个库,默认 0。 4.lettuce.pool: Lettuce 连接池配置。11.4 RedisTemplate 基本使用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.core.RedisTemplate; SpringBootTest public class RedisTemplateTest { Autowired private RedisTemplateString, Object redisTemplate; Test public void testString() { redisTemplate.opsForValue().set(name, tom); Object name redisTemplate.opsForValue().get(name); System.out.println(name); } }11.5 方法分组方法操作类型opsForValue()StringopsForList()ListopsForSet()SetopsForHash()HashopsForZSet()ZSetexpire()设置过期时间delete()删除 key11.6 StringRedisTemplateimport org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.stereotype.Service; import java.time.Duration; Service public class CodeService { private final StringRedisTemplate stringRedisTemplate; public CodeService(StringRedisTemplate stringRedisTemplate) { this.stringRedisTemplate stringRedisTemplate; } public void saveCode(String phone, String code) { String key code:login: phone; stringRedisTemplate.opsForValue().set(key, code, Duration.ofMinutes(5)); } public String getCode(String phone) { return stringRedisTemplate.opsForValue().get(code:login: phone); } }StringRedisTemplate: key 和 value 都按字符串处理。 学习和简单字符串场景更直观。11.7 RedisTemplate 序列化配置import com.fasterxml.jackson.annotation.JsonAutoDetect; import com.fasterxml.jackson.annotation.PropertyAccessor; import com.fasterxml.jackson.databind.ObjectMapper; 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.Jackson2JsonRedisSerializer; import org.springframework.data.redis.serializer.StringRedisSerializer; Configuration public class RedisConfig { Bean public RedisTemplateString, Object redisTemplate(RedisConnectionFactory factory) { RedisTemplateString, Object template new RedisTemplate(); template.setConnectionFactory(factory); StringRedisSerializer stringSerializer new StringRedisSerializer(); ObjectMapper objectMapper new ObjectMapper(); objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); Jackson2JsonRedisSerializerObject jsonSerializer new Jackson2JsonRedisSerializer(objectMapper, Object.class); template.setKeySerializer(stringSerializer); template.setHashKeySerializer(stringSerializer); template.setValueSerializer(jsonSerializer); template.setHashValueSerializer(jsonSerializer); template.afterPropertiesSet(); return template; } }为什么要配置序列化: 1.默认 JDK 序列化结果不方便人工查看。 2.String key 更清晰。 3.JSON value 更适合对象缓存。第十二章.Redis 配置文件12.1 网络配置配置说明bind绑定允许访问的 IPportRedis 服务端口默认 6379tcp-backlogTCP 连接队列timeout客户端空闲超时时间tcp-keepaliveTCP 心跳检测bind 127.0.0.1 port 6379 timeout 0 tcp-keepalive 30012.2 通用配置配置说明daemonize是否后台运行pidfile进程 id 文件databases数据库数量默认 16logfile日志文件dir工作目录daemonize yes pidfile /var/run/redis_6379.pid databases 16 dir ./12.3 安全配置requirepass 123456客户端认证:redis-cli auth 123456如果配置了 requirepass, 客户端必须认证后才能执行命令。12.4 内存限制配置配置说明maxclients最大客户端连接数maxmemory最大可用内存maxmemory-policy内存淘汰策略maxmemory-samples淘汰采样数量maxclients 10000 maxmemory 512mb maxmemory-policy allkeys-lru12.5 常见淘汰策略策略说明noeviction不淘汰写入时报错allkeys-lru所有 key 中淘汰最近最少使用volatile-lru设置过期时间的 key 中淘汰最近最少使用allkeys-random所有 key 中随机淘汰volatile-random设置过期时间的 key 中随机淘汰volatile-ttl设置过期时间的 key 中优先淘汰快过期的第十三章.Redis 事务和锁机制13.1 Redis 事务1.Redis 事务: 一次性、顺序性、排他性地执行一组命令。 2.核心命令: MULTI EXEC DISCARD WATCH UNWATCH13.2 事务基本使用multi set user:1:name tom set user:1:age 18 exec放弃事务:multi set a 1 discard13.3 watch 乐观锁watch balance:1001 multi decrby balance:1001 100 incrby balance:1002 100 exec1.watch 会监控 key。 2.如果事务执行前 key 被其他客户端修改,exec 会失败。 3.这是一种乐观锁思想。13.4 Redis 事务特点1.单独的 Redis 命令天然原子。 2.Redis 事务能保证命令按顺序执行。 3.Redis 事务不等同于 MySQL 事务。 4.Redis 事务中某条命令运行时报错,其他命令可能仍会执行。第十四章.Redis Lua 脚本14.1 Lua 的作用1.Lua: 一种轻量脚本语言。 2.Redis 支持执行 Lua 脚本。 3.核心价值: 把多条 Redis 命令作为一个脚本整体执行。 脚本执行具有原子性。14.2 Redis 执行 Luaeval return redis.call(get, KEYS[1]) 1 name参数说明:1.eval: 执行 Lua 脚本。 2.KEYS: 传入 key 数组。 3.ARGV: 传入普通参数数组。14.3 库存扣减 Lua 示例local stock tonumber(redis.call(get, KEYS[1])) local count tonumber(ARGV[1]) if stock nil then return -1 end if stock count then return 0 end redis.call(decrby, KEYS[1], count) return 1返回值含义: -1: 库存 key 不存在。 0: 库存不足。 1: 扣减成功。14.4 Spring Boot 执行 Luaimport org.springframework.core.io.ClassPathResource; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.data.redis.core.script.DefaultRedisScript; import org.springframework.stereotype.Service; import java.util.Collections; Service public class StockService { private final StringRedisTemplate stringRedisTemplate; public StockService(StringRedisTemplate stringRedisTemplate) { this.stringRedisTemplate stringRedisTemplate; } public Long deduct(String productId, String count) { DefaultRedisScriptLong script new DefaultRedisScript(); script.setLocation(new ClassPathResource(lua/deduct.lua)); script.setResultType(Long.class); String key stock: productId; return stringRedisTemplate.execute(script, Collections.singletonList(key), count); } }第十五章.Redis 持久化15.1 持久化的介绍1.Redis 主要基于内存保存数据。 2.服务重启后,内存数据会丢失。 3.持久化用于把内存数据保存到磁盘。 Redis 持久化方式: 1.RDB 2.AOF15.2 RDB 持久化1.RDB: Redis Database Backup。 2.方式: 在指定时间点生成内存数据快照。 3.结果文件: dump.rdb。RDB 相关命令save bgsave1.save: 同步保存,会阻塞 Redis。 2.bgsave: 后台保存,由子进程生成 RDB 文件。RDB 配置save 900 1 save 300 10 save 60 10000 dbfilename dump.rdb dir ./save 900 1: 900 秒内至少 1 个 key 发生变化,触发 RDB。RDB 优缺点类型内容优点文件紧凑适合备份恢复速度快缺点两次快照之间的数据可能丢失15.3 AOF 持久化1.AOF: Append Only File。 2.方式: 记录每一条写命令。 3.恢复: Redis 重启时重新执行 AOF 文件中的命令。AOF 配置appendonly yes appendfilename appendonly.aof appendfsync everysecappendfsync 策略策略说明always每次写命令都刷盘安全但慢everysec每秒刷盘常用折中方案no交给操作系统决定性能好但风险高AOF 优缺点类型内容优点数据丢失更少安全性更高缺点文件通常更大恢复速度可能慢于 RDB15.4 持久化选择1.只做缓存: 可以不开持久化,或只用 RDB。 2.数据比较重要: 开启 AOF everysec。 3.兼顾备份和安全: RDB AOF 同时开启。第十六章.Redis 主从复制16.1 主从复制的介绍1.主从复制: 一台 Redis 作为主节点 master。 多台 Redis 作为从节点 replica。 2.数据流向: 主节点数据同步到从节点。 3.常见用途: a.读写分离 b.数据备份 c.故障恢复基础16.2 主从复制作用作用说明读写分离主节点写从节点读容灾备份主节点异常时从节点有数据副本扩展读能力多个从节点分担读请求16.3 配置从节点replicaof 127.0.0.1 6379或者客户端执行:redis-cli -p 6380 replicaof 127.0.0.1 6379查看复制信息:info replication16.4 主从复制注意点1.默认情况下从节点主要负责读。 2.写操作通常在主节点执行。 3.主从复制存在延迟。 4.主节点宕机后,普通主从不会自动选主。第十七章.Redis 哨兵模式17.1 哨兵模式的介绍1.哨兵 Sentinel: Redis 高可用方案。 2.作用: a.监控主从节点状态 b.主节点宕机后自动选举新主节点 c.通知客户端新的主节点地址17.2 哨兵配置示例sentinel.conf:port 26379 sentinel monitor mymaster 127.0.0.1 6379 2 sentinel down-after-milliseconds mymaster 30000 sentinel parallel-syncs mymaster 1 sentinel failover-timeout mymaster 180000启动哨兵:redis-sentinel sentinel.conf17.3 哨兵工作流程哨兵监控 master ↓ 发现 master 无响应 ↓ 多个哨兵确认主观下线和客观下线 ↓ 从 slave 中选出新的 master ↓ 其他 slave 改为复制新 master ↓ 客户端获取新的 master 地址17.4 Spring Boot 连接哨兵spring: data: redis: sentinel: master: mymaster nodes: - 127.0.0.1:26379 - 127.0.0.1:26380 - 127.0.0.1:26381第十八章.Redis 集群18.1 为什么需要集群单机 Redis 的问题: 1.内存容量有限。 2.并发能力有限。 3.单点故障风险。 Redis Cluster: 1.通过分片保存数据。 2.多个 master 分担数据。 3.每个 master 可以配置 replica。18.2 Redis Cluster 的 slots1.Redis Cluster 有 16384 个槽位。 2.key 会通过算法映射到某个槽位。 3.槽位分配给不同 master。 4.访问 key 时,根据槽位找到对应节点。0 - 5460 - master1 5461 - 10922 - master2 10923 - 16383 - master318.3 搭建集群基本思路1.准备多个 Redis 实例。 2.每个实例使用不同端口和配置文件。 3.启动所有 Redis 实例。 4.使用 redis-cli --cluster create 创建集群。 5.指定副本数量。示例命令:redis-cli --cluster create \ 127.0.0.1:6379 127.0.0.1:6380 127.0.0.1:6381 \ 127.0.0.1:6382 127.0.0.1:6383 127.0.0.1:6384 \ --cluster-replicas 118.4 集群登录redis-cli -c -p 6379-c: 表示以集群模式连接,支持自动重定向到正确节点。18.5 查看集群信息cluster info cluster nodes18.6 集群优缺点类型内容优点扩展容量、分散压力、提高可用性缺点运维复杂、跨槽多 key 操作受限、事务支持受限18.7 Spring Boot 连接集群spring: data: redis: cluster: nodes: - 127.0.0.1:6379 - 127.0.0.1:6380 - 127.0.0.1:6381 - 127.0.0.1:6382 - 127.0.0.1:6383 - 127.0.0.1:6384第十九章.Redis 常见业务案例19.1 缓存穿透1.缓存穿透: 查询一个 Redis 和数据库都不存在的数据。 请求每次都会打到数据库。 2.解决思路: a.缓存空值 b.布隆过滤器 c.接口参数校验缓存空值示例:String key product: id; String json redisTemplate.opsForValue().get(key); if (json ! null) { return json; } Product product productMapper.selectById(id); if (product null) { redisTemplate.opsForValue().set(key, , Duration.ofMinutes(5)); return null; } redisTemplate.opsForValue().set(key, toJson(product), Duration.ofMinutes(30)); return product;19.2 缓存击穿1.缓存击穿: 热点 key 过期瞬间,大量请求同时访问数据库。 2.解决思路: a.热点 key 不过期 b.互斥锁重建缓存 c.逻辑过期19.3 缓存雪崩1.缓存雪崩: 大量 key 同时失效,导致请求集中打到数据库。 2.解决思路: a.过期时间加随机值 b.热点数据分批预热 c.Redis 高可用 d.服务限流降级19.4 分布式锁加锁:set lock:order:1001 uuid nx ex 30释放锁 Lua 思路:if redis.call(get, KEYS[1]) ARGV[1] then return redis.call(del, KEYS[1]) else return 0 end分布式锁注意: 1.加锁要设置过期时间。 2.value 要使用唯一标识。 3.释放锁要先判断 value,再删除。 4.判断和删除要用 Lua 保证原子性。