Redis官方文档
Redis速成(小白也可掌握)
安装
Linux终端输入:
1 2 3 4 5
| sudo apt install redis-server # 安装Redis
redis-cli --version # 安装后查看Redis版本
sudo nano /etc/redis/redis.conf # 修改Redis配置
|
在redis.conf
文件中进行如下修改:
1 2 3 4 5 6 7 8 9
| # 将绑定地址改为 0.0.0.0,让Redis可远程访问 # bind 127.0.0.1 ::1 bind 0.0.0.0
#取消注释 requirepass 启动密码认证,后面跟Redis密码 requirepass 自定义密码
# 以守护进程运行Redis daemonize yes
|
修改保存后重新启动Redis并登录:
1 2 3
| systemctl restart redis-server # 启动Redis
redis-cli -h 127.0.0.1 -p 6379 -a 密码 # 登录
|
数据类型
Redis有5种最常用的数据类型:
数据类型 |
样例 |
描述 |
String |
Hello World |
字符串 |
Hash |
{name: “saoke”, age: 18} |
JSON形式的字符串 |
List |
[A → B → B] |
有序列表,元素可重复 |
Set |
{A, B, C} |
无序集合,元素不可重复 |
SortedSet |
{A: 1, B: 2, C: 3} |
有序集合,元素不可重复 |
操作命令
可以在Redis官方文档查询。
String 类型
存储:set key value
获取
SpringBoot 操作 Redis
可使用SpringDataRedis
。 引入依赖:
1 2 3 4 5 6 7 8 9 10
| <dependencies> <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> </dependencies>
|
SpringDataRedis为了能使用对象作为键和值,实现了自动的序列化与反序列化。如果不经过自主配置,默认会对字符串键进行繁琐的序列化操作。
配置序列化方式:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| @Configuration public class RedisConfig {
@Bean public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) { RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(connectionFactory);
template.setKeySerializer(RedisSerializer.string()); template.setHashKeySerializer(RedisSerializer.string());
GenericJackson2JsonRedisSerializer jsonSerializer = new GenericJackson2JsonRedisSerializer(); template.setValueSerializer(jsonSerializer); template.setHashValueSerializer(jsonSerializer);
return template; } }
|
但由于使用JSON序列化器需要Redis中额外记录包名用于反序列化,占用了太多空间,实际开发中一般直接使用StringRedisTemplate
,程序员自己利用fastJson等工具转换JSON。
代码示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| @SpringBootTest class RedisTest {
@Autowired private StringRedisTemplate stringRedisTemplate;
@Autowired private RedisTemplate<String, Object> jsonRedisTemplate;
@Test public void stringRedisTemplateTest() { stringRedisTemplate.opsForValue().set("name", "骚客"); String name = stringRedisTemplate.opsForValue().get("name");
HashMap<String, String> map = new HashMap<>(); map.put("telephone", "13888888888"); map.put("password", "123456"); stringRedisTemplate.opsForHash().putAll("admin", map); Map<Object, Object> mapResult = stringRedisTemplate.opsForHash().entries("admin");
stringRedisTemplate.opsForHash().put("key", "field", "value"); String fieldResult = (String) stringRedisTemplate.opsForHash().get("key", "field"); }
@Test public void jsonSerializerTest() { jsonRedisTemplate.opsForValue().set("name", "骚客"); String name = (String) jsonRedisTemplate.opsForValue().get("name"); } }
|
缓存更新策略
可分为三类主动更新Redis的方案。
Write Through(写穿)
Write Back(写回)
只操作缓存,由其他线程异步地将缓存更新到数据库,保证最终一致。
Cache Aside(旁路缓存)
由程序员在代码中更新数据的同时操作缓存。
需要注意线程安全。操作数据库和缓存的先后顺序的两种情况都会导致数据不一致。


由于第二种方法只有当Redis中无该缓存数据时才会导致不一致,且Redis操作比数据库快,不容易被中断,因此先操作数据库再删除缓存更好。
缓存穿透
缓存穿透是指客户端请求的数据在缓存和数据库中都不存在,这样缓存永远都不会生效,这些请求都会到达数据库。
解决方法包括以下几种:
- 缓存空对象。当数据库查询不到时在Redis中缓存一个对应的null,并设置较短的过期时间。该方法的优点是简单方便,缺点是需要额外的缓存空间,如果有攻击者一直请求不存在的数据,缓存就会被占满。
- 布隆过滤器
- 增强查询id数据的复杂度,避免被猜测id规律
- 对请求数据进行合法性校验,可以直接排除一些无效请求
- 热点参数限流
缓存雪崩
缓存雪崩是指在同一时间大量的缓存key失效,或Redis服务器宕机,导致大量请求到达数据库。
例如,为了给缓存预热,提前把数据批量导入缓存,导致这批缓存的过期时间是一样的,就可能出现缓存雪崩。这种问题比较好解决,给过期时间加个随机数就好了。
对于Redis服务器宕机,可以搭建Redis集群,利用Redis的哨兵机制可以避免缓存雪崩。此外还可以给缓存业务添加降级限流策略,或给业务添加多级缓存,如Nginx、JVM和Redis的多级缓存。
缓存击穿
缓存击穿是指某个被高并发访问的key失效了,且重建该缓存比较耗时,则在重建缓存的过程中的大量请求都会到达数据库。
可以加上互斥锁重建缓存,当其他请求到来时获取不到锁说明已经在重建缓存了,则休眠一段时间再尝试查询缓存直到命中。

但该方法所有其他线程都只能等待缓存重建,性能较差,且如果重建缓存需要得到其他服务的锁,就容易造成死锁。
另一种方法逻辑过期,不为该热点缓存直接设置过期时间,而是把过期的时间作为数据的一部分存在value中,然后把重建缓存的任务开启一个专门的线程去做,这样线程通过value中的过期时间判断是否过期,若过期则尝试获取锁去开启重建缓存的线程,若获取锁失败说明已经在重建缓存了,则直接返回过期的数据。

这里的互斥锁可以用Redis中的setnx
指令实现(SpringDataRedis中是setIfAbsent
),只有在该键不存在时才能写入。setnx
相当于获取锁,del
删除相当于释放锁。
这种方法的优点是线程无需等待性能较好,缺点是实现复杂,不能保证一致性。
参观我的个人网站:http://saoke.fun