> 文章列表 > SpringBoot整合Redis、以及缓存穿透、缓存雪崩、缓存击穿的理解、如何添加锁解决缓存击穿问题?分布式情况下如何添加分布式锁

SpringBoot整合Redis、以及缓存穿透、缓存雪崩、缓存击穿的理解、如何添加锁解决缓存击穿问题?分布式情况下如何添加分布式锁

SpringBoot整合Redis、以及缓存穿透、缓存雪崩、缓存击穿的理解、如何添加锁解决缓存击穿问题?分布式情况下如何添加分布式锁

文章目录

    • 1、步骤
    • 2、具体过程
      • 1、引入pom依赖
      • 2、修改配置文件
      • 3、单元测试
      • 4、测试结果
    • 3、redis运行情况
    • 4、项目中实际应用
    • 5、加锁解决缓存击穿问题
      • 代码一(存在问题)
      • 代码二(问题解决)
    • 6、新问题
    • 7、分布式锁

三连哦

1、步骤

前提条件:已经安装了Redis

  • 1、pom中引入依赖
  • 2、配置文件中配置
  • 3、项目中使用

2、具体过程

1、引入pom依赖

版本由父工程管理

        <!--引入redis--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency>

SpringBoot整合Redis、以及缓存穿透、缓存雪崩、缓存击穿的理解、如何添加锁解决缓存击穿问题?分布式情况下如何添加分布式锁

2、修改配置文件

spring:redis:host: 192.168.202.211port: 6379

SpringBoot整合Redis、以及缓存穿透、缓存雪崩、缓存击穿的理解、如何添加锁解决缓存击穿问题?分布式情况下如何添加分布式锁

3、单元测试

这里有关stringRedisTemplate的使用、请自行查阅

    @AutowiredStringRedisTemplate stringRedisTemplate;@Testpublic void testRedis(){ValueOperations<String, String> ops = stringRedisTemplate.opsForValue();//保存ops.set("hello", UUID.randomUUID().toString());//查询String hello = ops.get("hello");System.out.println("之前保存的数据是:"+hello);}

4、测试结果

SpringBoot整合Redis、以及缓存穿透、缓存雪崩、缓存击穿的理解、如何添加锁解决缓存击穿问题?分布式情况下如何添加分布式锁

3、redis运行情况

我这里用docker安装redis、查看容器运行情况

SpringBoot整合Redis、以及缓存穿透、缓存雪崩、缓存击穿的理解、如何添加锁解决缓存击穿问题?分布式情况下如何添加分布式锁

4、项目中实际应用

代码逻辑
SpringBoot整合Redis、以及缓存穿透、缓存雪崩、缓存击穿的理解、如何添加锁解决缓存击穿问题?分布式情况下如何添加分布式锁

测试

访问接口数据
SpringBoot整合Redis、以及缓存穿透、缓存雪崩、缓存击穿的理解、如何添加锁解决缓存击穿问题?分布式情况下如何添加分布式锁

redis可视化工具查看

SpringBoot整合Redis、以及缓存穿透、缓存雪崩、缓存击穿的理解、如何添加锁解决缓存击穿问题?分布式情况下如何添加分布式锁

5、加锁解决缓存击穿问题

代码一(存在问题)

    @Override@Cacheable(value = {"category"},key = "#root.methodName",sync = true)public Map<String, List<Catalog2Vo>> getCatalogJsonDbWithSpringCache() {//1、缓存中放入json字符串,拿出json字符串,需要逆转为能用的对象类型【序列化和反序列化】String catalogJSON = stringRedisTemplate.opsForValue().get("catalogJSON");if(StringUtils.isEmpty(catalogJSON)){//2、缓存中没有,查询数据库Map<String, List<Catalog2Vo>> calogJsonFromDb = getCategoriesDb();//3、将查到的数据放入缓存,将对象转为json放在缓存中String s = JSON.toJSONString(calogJsonFromDb);stringRedisTemplate.opsForValue().set("catalogJSON",s,1, TimeUnit.DAYS);}System.out.println("直接取的缓存数据");//转为指定的对象Map<String, List<Catalog2Vo>> result = JSON.parseObject(catalogJSON,new TypeReference<Map<String, List<Catalog2Vo>>>(){});return result;}//从数据库中查出三级分类private  Map<String, List<Catalog2Vo>> getCategoriesDb() {synchronized (this){//得到锁以后,应该再去缓存中确定一次,如果缓存中没有需要继续查询String catalogJSON = stringRedisTemplate.opsForValue().get("catalogJSON");if(!StringUtils.isEmpty(catalogJSON)){//缓存中存在数据、直接返回Map<String, List<Catalog2Vo>> result = JSON.parseObject(catalogJSON,new TypeReference<Map<String, List<Catalog2Vo>>>(){});return result;}System.out.println("缓存中没有数据,查询了数据库");//优化业务逻辑,仅查询一次数据库List<CategoryEntity> categoryEntities = this.list();//查出所有一级分类List<CategoryEntity> level1Categories = getCategoryByParentCid(categoryEntities, 0L);Map<String, List<Catalog2Vo>> listMap = level1Categories.stream().collect(Collectors.toMap(k->k.getCatId().toString(), v -> {//遍历查找出二级分类List<CategoryEntity> level2Categories = getCategoryByParentCid(categoryEntities, v.getCatId());List<Catalog2Vo> catalog2Vos=null;if (level2Categories!=null){//封装二级分类到vo并且查出其中的三级分类catalog2Vos = level2Categories.stream().map(cat -> {//遍历查出三级分类并封装List<CategoryEntity> level3Catagories = getCategoryByParentCid(categoryEntities, cat.getCatId());List<Catalog2Vo.Catalog3Vo> catalog3Vos = null;if (level3Catagories != null) {catalog3Vos = level3Catagories.stream().map(level3 -> new Catalog2Vo.Catalog3Vo(level3.getParentCid().toString(), level3.getCatId().toString(), level3.getName())).collect(Collectors.toList());}Catalog2Vo catalog2Vo = new Catalog2Vo(v.getCatId().toString(), cat.getCatId().toString(), cat.getName(), catalog3Vos);return catalog2Vo;}).collect(Collectors.toList());}return catalog2Vos;}));return listMap;}}

使用jmeter对其进行压测

SpringBoot整合Redis、以及缓存穿透、缓存雪崩、缓存击穿的理解、如何添加锁解决缓存击穿问题?分布式情况下如何添加分布式锁

查看控制台情况,理想情况是数据库只查询一次。实际上查询了多次,出现这个问题的原因就是一个用户查询完数据后,就释放了锁。还未将数据写入缓存的时候,第二个用户又拿到了锁。这个时候缓存中还未进行数据缓存,导致再次查询数据库。需要优化代码逻辑

SpringBoot整合Redis、以及缓存穿透、缓存雪崩、缓存击穿的理解、如何添加锁解决缓存击穿问题?分布式情况下如何添加分布式锁

代码二(问题解决)

优化代码逻辑,压测过程同上。

SpringBoot整合Redis、以及缓存穿透、缓存雪崩、缓存击穿的理解、如何添加锁解决缓存击穿问题?分布式情况下如何添加分布式锁

SpringBoot整合Redis、以及缓存穿透、缓存雪崩、缓存击穿的理解、如何添加锁解决缓存击穿问题?分布式情况下如何添加分布式锁

6、新问题

本地锁在分布式情况下是锁不住的

7、分布式锁

待编辑