阶段四
public Map<String, List<Catalog2Vo>> getCatalogJsonDbWithRedisLock() { String uuid = UUID.randomUUID().toString(); ValueOperations<String, String> ops = stringRedisTemplate.opsForValue(); //为当前锁设置唯一的uuid,只有当uuid相同时才会进行删除锁的操作 Boolean lock = ops.setIfAbsent("lock", uuid,5, TimeUnit.SECONDS); if (lock) { Map<String, List<Catalog2Vo>> categoriesDb = getCategoryMap(); String lockValue = ops.get("lock"); if (lockValue.equals(uuid)) { try { Thread.sleep(6000); } catch (InterruptedException e) { e.printStackTrace(); } stringRedisTemplate.delete("lock"); } return categoriesDb; }else { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } return getCatalogJsonDbWithRedisLock(); } }
问题: 如果正好判断是当前值,正要删除锁的时候,锁已经过期,别人已经设置到了新的值。那么我们删除的是别人的锁
解决: 删除锁必须保证原子性。使用redis+Lua脚本完成
阶段五-最终形态
public Map<String, List<Catalog2Vo>> getCatalogJsonDbWithRedisLock() { String uuid = UUID.randomUUID().toString(); ValueOperations<String, String> ops = stringRedisTemplate.opsForValue(); Boolean lock = ops.setIfAbsent("lock", uuid,5, TimeUnit.SECONDS); if (lock) { Map<String, List<Catalog2Vo>> categoriesDb = getCategoryMap(); String lockValue = ops.get("lock"); String script = "if redis.call(\"get\",KEYS[1]) == ARGV[1] then\n" + " return redis.call(\"del\",KEYS[1])\n" + "else\n" + " return 0\n" + "end"; stringRedisTemplate.execute(new DefaultRedisScript<Long>(script, Long.class), Arrays.asList("lock"), lockValue); return categoriesDb; }else { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } return getCatalogJsonDbWithRedisLock(); } }
保证加锁【占位+过期时间】和删除锁【判断+删除】的原子性。更难的事情,锁的自动续期。
Spring Boot 基础就不介绍了,推荐看这个免费教程:
https://github.com/javastacks/spring-boot-best-practice
Redisson
Redisson是一个在Redis的基础上实现的Java驻内存数据网格(In-Memory Data Grid)。它不仅提供了一系列的分布式的Java常用对象,还提供了许多分布式服务。
其中包括(BitSet, Set, Multimap, SortedSet, Map, List, Queue, BlockingQueue, Deque, BlockingDeque, Semaphore, Lock, AtomicLong, CountDownLatch, Publish / Subscribe, Bloom filter, Remote service, Spring cache, Executor service, Live Object service, Scheduler service)
Redisson提供了使用Redis的最简单和最便捷的方法。Redisson的宗旨是促进使用者对Redis的关注分离(Separation of Concern),从而让使用者能够将精力更集中地放在处理业务逻辑上。
更多请参考官方文档:
https://github.com/redisson/redisson/wiki
来源:https://blog.csdn.net/zhangkaixuan456/article/details/110679617
————————————————