springboot整合redis以及缓存穿透缓存雪崩缓存击穿的理解如何添加锁解决缓存击穿问题?分布式情况下如何添加分布式锁(代码片段)

Mr.Aholic Mr.Aholic     2023-04-03     710

关键词:

文章目录

1、步骤

前提条件:已经安装了Redis

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

2、具体过程

1、引入pom依赖

版本由父工程管理

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

2、修改配置文件

spring:
  redis:
    host: 192.168.202.211
    port: 6379

3、单元测试

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

    @Autowired
    StringRedisTemplate stringRedisTemplate;

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

4、测试结果

3、redis运行情况

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

4、项目中实际应用

代码逻辑

测试

访问接口数据

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对其进行压测

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

代码二(问题解决)

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

6、新问题

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

7、分布式锁

待编辑

springboot整合redis缓存

...非常流行的NoSQL数据库(Redis)来实现我们的缓存需求。SpringBoot整合Redis是非常方便快捷的,我用的是Mybatis,这里就不说Springboot整合Mybatis了网上有很多,同样非常简单。下面进入正题: 查看详情

springboot整合redis实现缓存

...纲一、缓存的应用场景二、更新缓存的策略三、运行 springboot-mybatis-redis 工程案例四、springboot-mybatis-redis 工程代码配置详解 运行环境:MacOS10.12.xJDK8+Redis3.2.8SpringBoot1.5.1.RELEASE 一、缓存的应用场景什么是缓存?... 查看详情

shiro整合springboot缓存之redis实现(代码片段)

Shiro整合Springboot缓存之Redis实现Redis下载安装引入redis依赖配置redis连接启动redis服务自定义redis缓存的实现自定义shiro缓存管理器自定义salt实现实现序列化接口自定义Realm改造开启redis缓存Redis下载安装Windows系统中Redis下载安装其它... 查看详情

精通springboot--整合redis实现缓存

今天我们来讲讲怎么在springboot中整合redis实现对数据库查询结果的缓存。首先第一步要做的就是在pom.xml文件添加spring-boot-starter-data-redis。要整合缓存,必不可少的就是我们要继承一个父类CachingConfigurerSupport。我们先看看这个类... 查看详情

springboot整合redis缓存

使用springBoot添加redis缓存需要在POM文件里引入<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-cache</artifactId></dependency><dependency 查看详情

redis实现session管理以及缓存穿透与雪崩(代码片段)

...星,欢迎大家来互相助力我的链接redis实现session管理以及缓存穿透与雪崩一、Redis实现分布式Session管理1管理机制2开发Session管理1.引入依赖2.开发Session管理配置类3.打包测试即可二、缓存穿透与雪崩缓存穿透缓存击穿(量... 查看详情

redis缓存穿透,缓存击穿,缓存雪崩解决方案以及封装redis工具类(代码片段)

参考自黑马程序员缓存穿透缓存穿透:数据在数据库和redis中都不存在,请求直接打在数据库中。解决方案:方案一:方案二:代码案例实现: //缓存穿透privateShopcacheBreakDown(Longid)//查询redisStringjsonShop=(String)r... 查看详情

redis缓存穿透,缓存击穿,缓存雪崩解决方案以及封装redis工具类(代码片段)

参考自黑马程序员缓存穿透缓存穿透:数据在数据库和redis中都不存在,请求直接打在数据库中。解决方案:方案一:方案二:代码案例实现: //缓存穿透privateShopcacheBreakDown(Longid)//查询redisStringjsonShop=(String)r... 查看详情

redis缓存穿透,缓存击穿,缓存雪崩解决方案以及封装redis工具类(代码片段)

参考自黑马程序员缓存穿透缓存穿透:数据在数据库和redis中都不存在,请求直接打在数据库中。解决方案:方案一:方案二:代码案例实现: //缓存穿透privateShopcacheBreakDown(Longid)//查询redisStringjsonShop=(String)r... 查看详情

32springboot——缓存之整合redis

springboot缓存默认使用ConcurrentMapCacheManager 将数据保存在下面的Map中1、docker中开启Redis 2、添加Redis相关依赖<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-st 查看详情

springboot整合springcache,简化分布式缓存开发(代码片段)

前言上篇博文,我们深入的介绍了SpringBoot整合Redis的相关内容,处理缓存我们使用RedisTemplate或者StringRedisTemplate结合场景选择不同的数据结构,会造成缓存代码和业务代码会紧耦合在一起。有没有更加简便的方式呢... 查看详情

springboot整合redis实现缓存

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId><version>1.5.2.RELEASE</version></dependency& 查看详情

重学springboot系列之ehcache缓存,缓存问题(代码片段)

重学SpringBoot系列之EhCache缓存,缓存问题,session共享与redis分布式锁EhCache缓存整合SpringCache与Ehcache缓存的使用方法缓存使用中的坑缓存雪崩穿透等解决方案缓存使用的若干问题缓存穿透缓存击穿缓存雪崩redis缓存配置自定... 查看详情

springboot整合shiro集成redis缓存

简介:由于考虑到项目后期分布式部署,所以缓存由ehcache改为redis,而redis既有单机版部署,也有分布式部署,所以二者需要兼容。1.maven依赖<dependency><groupId>org.crazycake</groupId><artifactId>shiro-redis</artifactId><... 查看详情

springboot中使用redistemplate实现redis数据缓存

SpringBoot整合Redis数据库实现数据缓存的本质是整合Redis数据库,通过对需要“缓存”的数据存入Redis数据库中,下次使用时先从Redis中获取,Redis中没有再从数据库中获取,这样就实现了Redis做数据缓存。??按照惯例,下面一步一步... 查看详情

springboot2.0实战(23)整合redis之集成缓存springdatacache

SpringBoot2.0实战(23)整合Redis之集成缓存SpringDataCache来源:https://www.toutiao.com/a6803168397090619908/?timestamp=1584450221&app=news_article_lite&group_id=6803168397090619908&req_id=20200317210341 查看详情

springboot整合spring@cache和redis(代码片段)

转载请注明出处:https://www.cnblogs.com/wenjunwei/p/10779450.htmlspring基于注解的缓存对于缓存声明,spring的缓存提供了一组java注解:@Cacheable:触发缓存写入。@CacheEvict:触发缓存清除。@CachePut:更新缓存(不会影响到方法的运行)。@Caching:重新... 查看详情

springboot整合redis以及redis的简单使用

...多种数据结构的存储系统,用于缓存还是很方便的, springboot整合redis也很简单。 首先在pom文件里面加入redis的相关依赖: <!--Redis客户端--><dependency><groupId>redis.clients</groupId><artifac 查看详情