redisson 原理其实就是rediss+lua脚本的再次封装 用过redis应该知道 redis也是可以实现 分布式锁的 其实也是用到redis+lua脚本来保存解锁的原子性 但是过程比较麻烦且重复 所以redisson可以帮助我们更好的实现分布式锁
什么是lua脚本?
简单讲一下
Lua脚本在Redis中是以原子方式执行的,在Redis服务器执行 EVAL 命令时, 在命令执行完毕并向调用者返回结果之前,只会执行当前命令指定的Lua脚本包含的所有逻辑,其它客户端发送的命令将被阻塞 ,直到 EVAL 命令执行完毕为止。
多的不讲了大家想了解更多的 建议百度
讲一下spring整合redisson流程吧(这里我们配合spring cache一起用)
Redisson提供了将Redis无缝整合到Spring框架的能力。Redisson依照Spring Cache标准提供了基于Redis的Spring缓存实现。 每个缓存(Cache)实例都提供了了两个重要的可配置参数:过期时间(ttl)
和最长空闲时间(maxIdleTime)
,如果这两个参数都未指定或值为0
,那么实例管理的数据将永久保存。
第一步 添加依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<!--redisson-->
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>3.12.0</version>
</dependency>
第二步 编写配置文类和配置文件
redisson配置类
@Configuration
@ComponentScan
@EnableCaching
public static class Application {
@Bean(destroyMethod="shutdown")
RedissonClient redisson() throws IOException {
Config config = new Config();
config.useClusterServers()
.addNodeAddress("127.0.0.1:7004", "127.0.0.1:7001");
return Redisson.create(config);
}
@Bean
CacheManager cacheManager(RedissonClient redissonClient) {
Map<String, CacheConfig> config = new HashMap<String, CacheConfig>();
// 创建一个名称为"testMap"的缓存,过期时间ttl为24分钟,同时最长空闲时maxIdleTime为12分钟。
config.put("testMap", new CacheConfig(24*60*1000, 12*60*1000));
return new RedissonSpringCacheManager(redissonClient, config);
}
}
spring cache配置文件
#设置缓存组件类型
spring.cache.type=redis
#设置缓存过期时间
spring.cache.redis.time-to-live=3600000
#指定默认前缀,如果此处我们指定了前缀则使用我们指定的前缀,推荐此处不指定前缀
#spring.cache.redis.key-prefix=CACHE_
#是否开始前缀,建议开启
spring.cache.redis.use-key-prefix=true
#是否缓存空值,防止缓存穿透
spring.cache.redis.cache-null-values=true
配置并不多 下面用一个读写锁的案例展示一下使用的效果
@Autowired
RedissonClient redissonClient;
public Map<String, List<Catelog2Vo>> getCatalogJsonFromDbWithRedissonLock() {
//1、占分布式锁。去redis占坑
//RLock catalogJsonLock = redissonClient.getLock("catalogJson-lock");
//创建读锁
RReadWriteLock readWriteLock = redissonClient.getReadWriteLock("catalogJson-lock");
RLock rLock = readWriteLock.readLock();
Map<String, List<Catelog2Vo>> dataFromDb = null;
try {
rLock.lock();
//加锁成功...执行业务
dataFromDb = getDataFromDB();
} finally {
rLock.unlock();
}
return dataFromDb;
}
@Override
public Map<String, List<Catelog2Vo>> getCatalogJson() {
/**
* 1、空结果缓存:解决缓存穿透问题
* 2、设置过期时间(加随机值):解决缓存雪崩
* 3、加锁:解决缓存击穿问题
*/
String catelogJson = stringRedisTemplate.opsForValue().get("catelogJson");
if (StringUtils.isEmpty(catelogJson)) {
//缓存没有
Map<String, List<Catelog2Vo>> catalogJsonFromDB = getCatalogJsonFromDbWithRedissonLock();
return catalogJsonFromDB;
}
Map<String, List<Catelog2Vo>> res = JSON.parseObject(catelogJson, new TypeReference<Map<String, List<Catelog2Vo>>>() {
});
return res;
}
最后补充两句啊 :
并发 缓存 锁 三个关系还是很紧密的
缓存的出现其实也是为了降低并发的冲击力
- 缓存是将数据直接存入内容中,读取效率比数据库的更高
- 缓存可以有效地降低数据库压力,为数据库减轻负担
而锁呢(也就是这里的redisson )为的是避免并发时操作数据出现问题
缓存击穿就是一个很好的例子