redis分布式锁:
默认大家都对redis有了解~安装类使用之类的问题就直接跳过了。
先讲讲分布式锁的使用场景:
应用场景在分布式集群的环境中,一个服务的莫个缓存资源过期时,就有多个请求访问同一个资源 然后进行Db的查询,这时只能放一个请求过去减少对持久层数据库的压力,一个请求占到这个坑其他的请求就只能在外面等待,等待一段时间后可以再次来占坑,业务执行后,释放锁,那么其他请求在有需求查询数据库的时候就可以来占这个坑。
简易版:
使用的是redis的setnx(“lock”,“111”)
对应java的方法redisTemplate.opsForValue().setIfAbsent(“lock”, “111”)
public Map<String, List<Catelog2Vo>> gtCatalogJsonFromDbWithRedisLock() {
//1.占分布式锁,去redis占坑
Boolean lock = redisTemplate.opsForValue().setIfAbsent("lock", "111");
if(lock){
//加锁成功...执行业务
Map<String, List<Catelog2Vo>> fromDb = getDataFromDb();
redisTemplate.delete("lock");//删除锁
return fromDb;
}else {
//加锁失败。。。重试。 自旋的方式
//避免重试的频率过高 可以休眠100毫秒 这个数值根据各自情况设置
return gtCatalogJsonFromDbWithRedisLock();
}
}
问题一:
这里出现的第一个问题:
1.setnx占位后,业务代码出现异常或者程序在执行过程中宕机。都没有执行删除的逻辑。照成死锁。
解决:设置锁自动过期,即使没有删除,会自动删除。
自动解锁版:
换一个带时间参数的方法即可
加锁设置过期时间,必须和加锁是同步的 需要原子性
public Map<String, List<Catelog2Vo>> gtCatalogJsonFromDbWithRedisLock() {
//1.占分布式锁,去redis占坑
Boolean lock = redisTemplate.opsForValue().setIfAbsent("lock", "111",300, TimeUnit.SECONDS);
//2.设置过期时间,必须和加锁是同步的,原子的
if(lock){
//加锁成功...执行业务
Map<String, List<Catelog2Vo>> fromDb = getDataFromDb();
redisTemplate.delete("lock");//删除锁
return fromDb;
}else {
//加锁失败。。。重试。 自旋的方式
//避免重试的频率过高 可以