Redis的使用
思考:
redis的序列化
-
序列化是将数据转成二进制数据,理解为Object–》byte[]
-
反序列化是将二进制数据转成其他数据,理解为byte[]–》Object
-
reidsTemple源码有key、value、hashkey、hashvalue、string五种序列化的属性值。
StringSerializer=new StringRedisSerializer();
其他四种一般在xml文件生成redisTemple的时候配置property来指定,不指定默认使用默认的序列化方式: jdk序列化方式。
也可以像指定四种方式一样指定默认序列化方式,这样就不用指定四种序列化方式了。(各序列化的区别链接:)
-
可以存的时候使用序列化存,取的时候也用序列化取。各种序列化都实现接口RedisSerializer。里面有序列化serialize,反序列化deserialize。例如:new StringRedisSerializer().serialize()。使用字符串序列化方式序列化。
-
redisTemplate.getValueSerializer()获取value的序列化器
RedisConnection
- execute() 需要 RedisConnection 对象,通过 RedisConnection 操作 Redis 被称为低级抽象(Low-Level Abstractions)
- opsFor 之类的被称为高级抽象(High-Level Abstractions),是为了提供更友好的模板类,底层还是调用的 execute(),需要 RedisConnection 对象。所以我觉得 opsFor 就是对 execute() 的进一步封装。
- 通过redisconnection可以直接执行redis命令
锁
简述:
- 分布式锁必须设置过期时间,节点坏了也可以保证锁可以自动过期。
- 锁的操作中,设置锁和删除锁两个操作必须原子性。
- redis默认的是永不过期,单体锁可以永不过期,分布式锁不可以。
分布式锁特点:
- 独享: 即互斥属性,在同一时刻,一个资源只能有一把锁被一个客户端持有
- 无死锁: 当持有锁的客户端奔溃后,锁仍然可以被其它客户端获取
- 容错性: 当部分节点失活之后,其余节点客户端依然可以获取和释放锁
- 统一性: 即释放锁的客户端只能由获取锁的客户端释放
- 简而言之:可以判断原加锁对象解锁,有过期时间,多redis节点加锁,删锁和加锁操作保证原子性
单体锁特点:
- 可以永不过期
- 删锁和加锁操作保证原子性
- 直接使用setIfAbsent就可以实现单体锁
redis能用的的加锁命令只有SETNX
SETNX
将 key 的值设为 value,当且仅当 key 不存在。
原子性操作,不可以设置过期时间,很容易出现错误。
一般通过lua或者事务加上过期时间保证原子性实现分布式锁
redistemple.opsForValue().setIfAbsent()底层就是使用redisConnection.setNX()。
incr和set会出现重复加锁,不能判断是否重复,也不能保证原子性操作。set会覆盖,incr会在原基础+1。
redis锁的演进过程:思想可以,但stringredistemple版本不清楚
- 可以参考其分布式锁,配合aop切面实现切面加锁。
- 其分布式锁依赖部分lua和原子性操作,但流程还是可以帮助理解的。
链接
加锁应用01:经典错误示范:这是个单体结构的redis锁,其实没有过期时间
加速应用03: 通过set(time)+lua脚本实现分布锁锁
加锁应用04:通过set(time)+lua脚本实现分布锁锁
redis加锁命令
典型的错误实现,在早期的 redis 分布式锁实践中我们经常可以看到类似的实现,其中 spring-boot 中的 setIfAbsent 方法在底层调用的是 redis 的 setNx 命令,该命令和 set 命令的 NX 选项具有同样的功能,但是 setNx 命令不能够设置 key 的有效期,这也是为什么我们会在获取到锁之后马上去设置锁的有效期,但是恰好这里却隐藏着风险,因为这一整个操作并非是原子的。
待学
摸鱼的猫:
redis的发布订阅
摸鱼的猫:
redis的事务监视