分布式锁结合SpringCache( 二 )

level3Catalog = getParent_cid(l2);List level3Catalog = getParent_cid(selectList, l2.getCatId());if (level3Catalog != null) {List collect = level3Catalog.stream().map(l3 -> {Catalog2Vo.Catalog3Vo catalog3Vo = new Catalog2Vo.Catalog3Vo(l2.getCatId().toString(), l3.getCatId().toString(), l3.getName());return catalog3Vo;}).collect(Collectors.toList());catalog2Vo.setCatalog3List(collect);}return catalog2Vo;}).collect(Collectors.toList());}return catalog2Vos;}));//3、放入缓存中String s = JSON.toJSONString(parent_cid);//1, TimeUnit.DAYS 空结果缓存:解决缓存穿透;设计过期时间:解决雪崩redisTemplate.opsForValue().set("catalogJSON", s, 1, TimeUnit.DAYS);return parent_cid;}3、分布式锁原理与使用由于本地锁只能管理本地服务的事务 , 所以在分布式微服务中引进了分布式锁
1、分布式锁演进:
分布式锁结合SpringCache文章插图
1.1、分布式锁阶段一:
分布式锁结合SpringCache文章插图
1.2、分布式锁阶段二:
分布式锁结合SpringCache文章插图
1.3、 分布式锁阶段三:
分布式锁结合SpringCache文章插图
1.4、分布式锁阶段四:
分布式锁结合SpringCache文章插图
1.5、演进代码:public Map> getCatalogJsonFromDbWithRedisLock() {//1、占分布式锁 , 去redis占坑同时加锁成功(原子性) , 设置过期时间(30秒) 。 假设过程出问题直接过期不会发生死锁 , 改进第阶段1和阶段2 , 使用setIfAbsent原子命令将获取锁和过期时间同时设置String uuid = UUID.randomUUID().toString();Boolean lock = redisTemplate.opsForValue().setIfAbsent("lock", uuid, 300, TimeUnit.SECONDS);if (lock) {System.out.println("获取分布式锁成功");Map> dataFromDb;try {//执行业务dataFromDb = getDataFromDb();} finally {//删除锁.redisTemplate.opsForValue().get("lock")获取需要时间释放锁 , 存在“不可重复读” , 所以获取后删除过程也要要求原子性;/*String lockValue = http://kandian.youth.cn/index/redisTemplate.opsForValue().get("lock");if (uuid.equals(lockValue)){redisTemplate.delete("lock");}*///使用脚本 , 改进阶段4String script = "if redis.call('get',KEYS[1]) == ARGV[1] then return redis.call('del',KEYS[1]) else return 0 end";//publicT execute(RedisScript script, List keys, Object... args)//采用随机的uuid值 , 改进阶段3Long lock1 = redisTemplate.execute(new DefaultRedisScript(script, Long.class), Arrays.asList("lock"), uuid);}return getDataFromDb();} else {System.out.println("获取分布式锁失败");try {Thread.sleep(200);} catch (Exception e) {}//加锁失败 , 设定时间进行重试return getCatalogJsonFromDbWithRedisLock();//自旋方式}}4、Redisson实践:1、Redisson官方文档:2、Redisson可重用锁: @ResponseBody@GetMapping("/hello")public String hello(){RLock lock= redisson.getLock("my-lock");lock.lock(10, TimeUnit.SECONDS);//这种方法不会自动续期//Redisson功能://1、可以锁的自动续期 , 如果业务超长 , 因此不用担心业务时间过长自动删锁//2、枷锁业务只要运行完成 , 就不会给当业务续期 。 默认是30s后自动删锁try{//模拟业务超长执行System.out.println("加锁成功"+Thread.currentThread().getId());Thread.sleep(30000);} catch (InterruptedException e) {e.printStackTrace();} finally {lock.unlock();}return "hello";}


推荐阅读