当前位置:网站首页>Distributed Lock-Redission - Cache Consistency Solution

Distributed Lock-Redission - Cache Consistency Solution

2022-08-11 07:51:00 flower padded jacket

🧑‍ 个人主页:花棉袄

本章内容:【Redission - 缓存一致性解决
版权: 本文由【花棉袄】原创在CSDN首发需要转载请联系博主

在这里插入图片描述

Redission - 缓存一致性解决

️如果文章对你有帮助【关注点赞️收藏】

双写模式

在这里插入图片描述

  • 两个线程写 In the end, only one thread writes successfully,If the post-write is successful, the previously written data will be overwritten,This creates dirty data

失效模式

在这里插入图片描述

三个连接

Connection number one 写数据库 然后删缓存

connection number two The network connection is slow when writing to the database,The writing has not been successful yet

Link number three 直接读取数据,What is read is the data written by connection No. 1,此时 The second link successfully writes data and deletes the cache,No. 3 began to update the cache and found that it was the cache of No. 2 that was updated

解决方案

无论是双写模式还是失效模式,Will come to this cache inconsistency problem,That is, if multiple strengths are updated at the same time, something will happen,怎么办?

1、If it is user purity data(订单数据、用户数据),There is very little chance of this concurrency,There is almost no need to think about it,缓存数据加上过期时间,每隔一段时间触发读的主动更新即可
2、如果是菜单,商品介绍等基础数据,也可以去使用 canal 订阅,binlog 的方式
3、缓存数据 + The expiration time is also sufficient to meet the cache requirements of most businesses
4、通过加锁保证并发读写,Line up in order as you write,读读无所谓,So it is suitable for read-write locks,(业务不关心脏数据,允许临时脏数据可忽略)
  • 总结:
The data we can put into the cache should never be real-time、一致性要求超高的.所以缓存数据的时候加上过期时间,Make sure to get the current latest value every day
我们不应该过度设计,增加系统的复杂性
遇到实时性、一致性要求高的数据,就应该查数据库,即使慢点

配置Redission

  • 引入依赖
<!-- https://mvnrepository.com/artifact/org.redisson/redisson -->
<dependency>
    <groupId>org.redisson</groupId>
    <artifactId>redisson</artifactId>
    <version>3.15.5</version>
</dependency>
  • 自定义配置类
@Configuration
public class MyRedissonConfig {
    
    /** * 对 Redisson 的使用都是通过 RedissonClient 对象 * @return * @throws IOException */
    @Bean(destroyMethod="shutdown") // 服务停止后调用 shutdown 方法.
    public RedissonClient redisson() throws IOException {
    
        // 1.创建配置
        Config config = new Config();
        // 集群模式
        // config.useClusterServers().addNodeAddress("127.0.0.1:7004", "127.0.0.1:7001");
        // 2.根据 Config 创建出 RedissonClient 示例.
        config.useSingleServer().setAddress("redis://127.0.0.1:6379");
        return Redisson.create(config);
    }
}
  • 使用分布式锁Redission解决缓存一致性问题
  public Map<String, List<Catelog2Vo>> getCatalogJsonFromDbWithRedisLock() {
    
        String uuid = UUID.randomUUID().toString();
        // Setting the value also sets the expiration time
        Boolean lock = redisTemplate.opsForValue().setIfAbsent("lock", uuid, 300, TimeUnit.SECONDS);
        if (lock) {
    
            // 加锁成功..执行业务
            // 设置过期时间,必须和加锁是同步的,原子的
            Map<String, List<Catelog2Vo>> dataFromDb;
            try {
    
                dataFromDb = getCatelogJsonFromDb();
            } finally {
    
                String script = "if redis.call('get',KEYS[1]) == ARGV[1] then return redis.call('del',KEYS[1]) else return 0 end";
                //删除锁
                Long lock1 = redisTemplate.execute(new DefaultRedisScript<Long>(script, Long.class), Arrays.asList("lock"), uuid);
            }
            return dataFromDb;
        } else {
    
            // 加锁失败,重试 synchronized()
            // 休眠200ms重试
            System.out.println("获取分布式锁失败,等待重试");
            try {
    
                TimeUnit.MILLISECONDS.sleep(200);
            } catch (InterruptedException e) {
    
                e.printStackTrace();
            }
            return getCatalogJsonFromDbWithRedisLock();
        }
    }

    //三级分类
    public Map<String, List<Catelog2Vo>> getCatelogJsonFromDb() {
    
            // 0.After getting the lock, get it from the cache
            String catelogJSON = redisTemplate.opsForValue().get("categoryJSON");
            if (!StringUtils.isEmpty(catelogJSON)) {
    
                // Convert to the object we specify
                Map<String, List<Catelog2Vo>> result = JSON.parseObject(catelogJSON, new TypeReference<Map<String, List<Catelog2Vo>>>() {
    
                });
                System.out.println("获得锁-从缓存中获取");
                return result;
            }
            System.out.println("获得锁-查询了数据库");
            //Turns multiple queries of the database into one query
            List<CategoryEntity> selectList = baseMapper.selectList(null);
            //1.查询所有一级分类
            List<CategoryEntity> categoryOne = getParent_cid(selectList, 0L);
            //2.封装数据
            Map<String, List<Catelog2Vo>> collect = categoryOne.stream().collect(Collectors.toMap(k -> k.getCatId().toString(), v -> {
    
                //2.1根据一级分类ID查询二级分类
                List<CategoryEntity> categoryTwo = getParent_cid(selectList, v.getCatId());
                List<Catelog2Vo> catelog2Vos = null;
                if (categoryTwo != null) {
    
                    //2.2 封装二级分类
                    catelog2Vos = categoryTwo.stream().map(levelTwo -> {
    
                        Catelog2Vo catelog2Vo = new Catelog2Vo(v.getCatId().toString(), null, levelTwo.getCatId().toString(), levelTwo.getName().toString());
                        List<CategoryEntity> categoryThree = getParent_cid(selectList, levelTwo.getCatId());
                        if (categoryThree != null) {
    
                            List<Catelog2Vo.Catelog3Vo> catalog3List = categoryThree.stream().map(levelThree -> {
    
                                //2.3 Packaging three-level classification
                                Catelog2Vo.Catelog3Vo catelog3Vo = new Catelog2Vo.Catelog3Vo(levelTwo.getCatId().toString(), levelThree.getCatId().toString(), levelThree.getName().toString());
                                return catelog3Vo;
                            }).collect(Collectors.toList());
                            //Set up three-level classification
                            catelog2Vo.setCatalog3List(catalog3List);
                        }
                        return catelog2Vo;
                    }).collect(Collectors.toList());
                }
                return catelog2Vos;
            }));
            return collect;
        }
原网站

版权声明
本文为[flower padded jacket]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/223/202208110653592356.html