第一章.NoSQL 数据库
1.1 什么是 NoSQL
1.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 数据库
| 数据库 | 类型 | 特点 |
|---|---|---|
| Redis | Key-Value | 内存数据库,速度快,支持多种数据结构 |
| Memcached | Key-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 | 按模式查询 key |
exists key | 判断 key 是否存在 |
type key | 查看 key 对应 value 类型 |
del key | 删除 key |
expire key seconds | 设置过期时间 |
ttl key | 查看剩余过期时间 |
rename old new | 重命名 key |
dbsize | 查看当前库 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 和 flush
keys *会扫描所有 key,数据量大时可能阻塞 Redis;flushdb和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 value | key 不存在时才设置 |
mset k1 v1 k2 v2 | 批量设置 |
mget k1 k2 | 批量获取 |
incr key | 数值加 1 |
decr key | 数值减 1 |
incrby key n | 数值增加 n |
append 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 name=tom age=18 phone=138000000007.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 | 获取全部 field |
hvals key | 获取全部 value |
hincrby 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 用户登录 token
setex 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> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>5.1.0</version> </dependency>10.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 整合 Redis
11.1 Spring Data Redis
1.Spring Data Redis: Spring 提供的 Redis 操作封装。 2.常用核心对象: RedisTemplate StringRedisTemplate 3.好处: 和 Spring Boot 自动配置、连接池、序列化机制整合更方便。11.2 添加依赖
<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>11.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 RedisTemplate<String, Object> redisTemplate; @Test public void testString() { redisTemplate.opsForValue().set("name", "tom"); Object name = redisTemplate.opsForValue().get("name"); System.out.println(name); } }11.5 方法分组
| 方法 | 操作类型 |
|---|---|
opsForValue() | String |
opsForList() | List |
opsForSet() | Set |
opsForHash() | Hash |
opsForZSet() | ZSet |
expire() | 设置过期时间 |
delete() | 删除 key |
11.6 StringRedisTemplate
import 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 RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) { RedisTemplate<String, Object> template = new RedisTemplate<>(); template.setConnectionFactory(factory); StringRedisSerializer stringSerializer = new StringRedisSerializer(); ObjectMapper objectMapper = new ObjectMapper(); objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); Jackson2JsonRedisSerializer<Object> 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 | 绑定允许访问的 IP |
port | Redis 服务端口,默认 6379 |
tcp-backlog | TCP 连接队列 |
timeout | 客户端空闲超时时间 |
tcp-keepalive | TCP 心跳检测 |
bind 127.0.0.1 port 6379 timeout 0 tcp-keepalive 30012.2 通用配置
| 配置 | 说明 |
|---|---|
daemonize | 是否后台运行 |
pidfile | 进程 id 文件 |
databases | 数据库数量,默认 16 |
logfile | 日志文件 |
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 执行 Lua
eval "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 执行 Lua
import 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) { DefaultRedisScript<Long> 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 优缺点
| 类型 | 内容 |
|---|---|
| 优点 | 数据丢失更少,安全性更高 |
| 缺点 | 文件通常更大,恢复速度可能慢于 RDB |
15.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 的 slots
1.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 保证原子性。