缓存学习-redis,redisson分布式锁,SpringCache缓存使用

缓存学习-redis,redisson分布式锁,SpringCache缓存使用

文章目录

  • 缓存学习-redis,redisson分布式锁,SpringCache缓存使用
  • 前言
  • 一、redis使用步骤
    • 1.引入pom依赖
    • 2.配置文件yml
    • 2.使用redis
  • 二、redisson分布式锁使用步骤
    • 1.引入pom依赖
    • 2.编写redisson配置类
    • 3.使用redisson
  • 三、SpringCache缓存使用步骤
    • 1.引入pom依赖
    • 2.修改配置文件yml
    • 3.编写自定义配置类
    • 4.使用
  • 再见


前言

这里介绍一下,redis整合Springboot的简单使用


一、redis使用步骤

1.引入pom依赖

代码如下(示例):

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

2.配置文件yml

代码如下(示例):

spring:
  #redis配置
  redis:
    host: localhost
    port: 6379

2.使用redis

代码如下(示例):

@RunWith(SpringRunner.class)
@SpringBootTest
@Slf4j
public class ProductApplicationTest {
    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Test
    public void test02(){
        ValueOperations<String, String> valueOperations = stringRedisTemplate.opsForValue();
        valueOperations.set("name","bgg");
        System.out.println("-----:"+valueOperations.get("name"));
    }
}

二、redisson分布式锁使用步骤

1.引入pom依赖

代码如下(示例):

     <!-- 使用redis的分布式锁 -->
        <dependency>
            <groupId>org.redisson</groupId>
            <artifactId>redisson</artifactId>
            <version>3.16.4</version>
        </dependency>
        <!-- boot整合更方便 但是为了学习先使用上面-->
<!--        <dependency>-->
<!--            <groupId>org.redisson</groupId>-->
<!--            <artifactId>redisson-spring-boot-starter</artifactId>-->
<!--            <version>3.16.4</version>-->
<!--        </dependency>-->

2.编写redisson配置类

代码如下(示例):

package com.bgg.gulimall.product.config;

import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * 配置redisson
 * @author lmc
 * @date 2021/11/19 14:07
 */
@Configuration
public class MyRedissonConfig {

    /**
     * 所有redisson的使用,都通过RedissonClient对象
     * @return
     */
    @Bean(destroyMethod = "shutdown")
    public RedissonClient redisson(){
        Config config = new Config();
        //协议 redis:/rediss:
        config.useSingleServer().setAddress("redis://127.0.0.1:6379");
        return Redisson.create(config);
    }
}

3.使用redisson

代码如下(示例):使用redis缓存数据,并加锁

     /**
     * redis中查分类信息
     * bug:  springboot整合redis,默认使用的是lettuce,会出现堆外内存不足的异常,因为没有清理
     * 解决:1.升级lettuce客户端   2.使用jedis(这是旧的,长时间未更新,暂时如此  pom.xml中修改)
     * @return
     */
    //TODO  redis bug待解决
    public Map<String, List<Catalog2Vo>> getCatelogJson1() {
        /**
         * 1.空结果缓存:解决缓存穿透
         * 2.设置过期时间(加随机值):解决缓存雪崩
         * 3.加锁:解决缓存击穿
         */
        //1.加入缓存逻辑,存json字符串 json跨语言跨平台   序列化与反序列化
        String catelogJson = redisTemplate.opsForValue().get("catelogJson");
        if(StringUtils.isBlank(catelogJson)){
            //2.缓存中没有,再从数据库查,并放入缓存
            Map<String, List<Catalog2Vo>> map  = this.getCatelogJsonFromRedissonLock();
//            //3.放入缓存
//            catelogJson = JSON.toJSONString(map);
//            redisTemplate.opsForValue().set("catelogJson",catelogJson);
            return map;
        }
        return JSON.parseObject(catelogJson, new TypeReference<Map<String, List<Catalog2Vo>>>(){});
    }

    /**
     * 在数据库中查分类信息
     * 加锁:redisson分布式锁
     * @return
     */
    public Map<String, List<Catalog2Vo>> getCatelogJsonFromRedissonLock() {
        Map<String, List<Catalog2Vo>> map = null;
        RLock lock = redisson.getLock("catelogJson-lock");
        lock.lock(40, TimeUnit.SECONDS);
        try {
            Thread.sleep(20000);
            map = this.getDataFromDB();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
        return map;
    }


    /**
     * 在数据库中查分类信息
     * 加锁:单体应用
     * @return
     */
    public synchronized Map<String, List<Catalog2Vo>> getCatelogJsonFroDB() {
        //先确认缓存中有无
        String catelogJson = redisTemplate.opsForValue().get("catelogJson");
        if(StringUtils.isNotBlank(catelogJson)){
            log.info("缓存命中--直接返回");
            return JSON.parseObject(catelogJson,new TypeReference<Map<String, List<Catalog2Vo>>>(){});
        }
        log.info("缓存未命中--进行查库");

        //代码性能优化:先查出所有分类数据,再进行筛选,减少与数据库的交互,进而提高性能
        List<CategoryEntity> all = this.baseMapper.selectList(new LambdaQueryWrapper<CategoryEntity>());
        if(all == null){
            return null;
        }

        //1.先查出所有的一级分类
        List<CategoryEntity> level1Category = getLevel1Category();
        //2.封装
        Map<String, List<Catalog2Vo>> map = level1Category.stream().collect(Collectors.toMap(k -> k.getCatId().toString(), v -> {
            //2.1查出二级分类
            List<CategoryEntity> catelog2List = all.stream().filter(i -> i.getParentCid().longValue() == v.getCatId().longValue()).collect(Collectors.toList());
//            List catelog2List = this.baseMapper.selectList(new LambdaQueryWrapper().eq(CategoryEntity::getParentCid, v.getCatId()));

            List<Catalog2Vo> collect = null;
            if(null != catelog2List){
                collect = catelog2List.stream().map(i -> {
                    //3.1查出三级分类
                    List<CategoryEntity> catelog3List = all.stream().filter(e -> e.getParentCid().longValue() == i.getCatId().longValue()).collect(Collectors.toList());
//                    List catelog3List = this.baseMapper.selectList(new LambdaQueryWrapper().eq(CategoryEntity::getParentCid, i.getCatId()));
                    List<Catalog2Vo.Catalog3Vo> catelog3Vos = null;
                    if(null != catelog3List){
                        catelog3Vos = catelog3List.stream().map(j -> {
                            Catalog2Vo.Catalog3Vo catelog3Vo = new Catalog2Vo.Catalog3Vo();
                            catelog3Vo.setCatalog2Id(i.getCatId().toString());
                            catelog3Vo.setId(j.getCatId().toString());
                            catelog3Vo.setName(j.getName());
                            return catelog3Vo;
                        }).collect(Collectors.toList());
                    }
                    Catalog2Vo catalog2Vo = new Catalog2Vo();
                    catalog2Vo.setCatalog1Id(v.getCatId().toString());
                    catalog2Vo.setCatalog3List(catelog3Vos);
                    catalog2Vo.setId(i.getCatId().toString());
                    catalog2Vo.setName(i.getName());
                    return catalog2Vo;
                }).collect(Collectors.toList());
            }

            return collect;
        }));
        //数据加入缓存
        redisTemplate.opsForValue().set("catelogJson",JSON.toJSONString(map));
        return map;
    }                                                                                                                        

三、SpringCache缓存使用步骤

1.引入pom依赖

代码如下(示例):

 <!--使用springCache缓存 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-cache</artifactId>
        </dependency>

2.修改配置文件yml

代码如下(示例):

  #缓存配置
spring:
  cache:
    type: redis         #缓存使用redis
    redis:
      time-to-live: 3600000     #缓存存活时间1h
     # key-prefix: CACHE_        #设置缓存前缀名
      use-key-prefix: true      #是否使用前缀
      cache-null-values: true   #是否缓存null值  可防止缓存穿透

3.编写自定义配置类

代码如下(示例):

package com.bgg.gulimall.product.config;

import com.alibaba.fastjson.support.spring.GenericFastJsonRedisSerializer;
import org.springframework.boot.autoconfigure.cache.CacheProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.StringRedisSerializer;

/**
 *自定义缓存配置
 * @author lmc
 * @date 2021/11/25 16:22
 */
@EnableConfigurationProperties(CacheProperties.class)//开启配置文件
@Configuration
@EnableCaching
public class MyCacheConfig {

    @Bean
    RedisCacheConfiguration redisCacheConfiguration(CacheProperties cacheProperties){
        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig();

        //springCach默认redis缓存的是java序列化  现在自定义为json串
        config = config.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()));
        config = config.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericFastJsonRedisSerializer()));

        //将配置文件的内容生效
        CacheProperties.Redis redisProperties = cacheProperties.getRedis();
        if (redisProperties.getTimeToLive() != null) {
            config = config.entryTtl(redisProperties.getTimeToLive());
        }
        if (redisProperties.getKeyPrefix() != null) {
            config = config.prefixCacheNameWith(redisProperties.getKeyPrefix());
        }
        if (!redisProperties.isCacheNullValues()) {
            config = config.disableCachingNullValues();
        }
        if (!redisProperties.isUseKeyPrefix()) {
            config = config.disableKeyPrefix();
        }

        return config;
    }
}

4.使用

代码如下(示例):

   /**
     * @CacheEvict: 缓存失效
     * @param category
     */
    //@CacheEvict(value = "category",key = "'getLevel1Category'")
//    @Caching(evict = { //指定删除多个缓存
//            @CacheEvict(value = "category",key = "'getLevel1Category'"),
//            @CacheEvict(value = "category",key = "'getCatelogJson'")
//    })
    @CacheEvict(value = "category",allEntries = true) //删除category分区的所有缓存
    @Transactional
    @Override
    public void updateCascade(CategoryEntity category) {
        this.updateById(category);
        if(!StringUtils.isBlank(category.getName())){
            categoryBrandRelationService.updateCategory(category.getCatId(),category.getName());
        }
    }

    /**
     * 1.每一个需要缓存的数据我们都来指定一个名字,【缓存的分区--根据业务类型区分】
     * @Cacheable("category") //代表当前方法的结果需要缓存,若缓存中有,则不调用方法,否者调用
     *
     * 2.默认行为:
     *  若缓存中有,则不调用方法
     *  key默认生成名字:category::SimpleKey []
     *  缓存的值默认java序列后话的数据
     *  默认过期时间-1:永不过期
     *
     * 3.自定义行为:
     *  指定key名字   key属性指定,接收一个spEL或者直接单引号名 'level1Category'
     *  指定过期时间  yml配置
     *  缓存值改为json字符串格式
     *
     * 4.   * 1.空结果缓存:解决缓存穿透   (yml配置文件)
     *      * 2.设置过期时间:解决缓存雪崩  (yml配置文件)
     *      * 3.加锁:解决缓存击穿    sync = true:这是一个单机同步锁,足以解决缓存击穿的问题
     * @return
     */
    @Cacheable(value = "category",key = "#root.methodName",sync = true)
    @Override
    public List<CategoryEntity> getLevel1Category() {
        System.out.println("调用了方法getLevel1Category");
        List<CategoryEntity> categoryEntityList = this.baseMapper.selectList(new LambdaQueryWrapper<CategoryEntity>()
                .eq(CategoryEntity::getParentCid, 0));
        return categoryEntityList;
    }



    @Cacheable(value = "category",key = "#root.methodName")
    @Override
    public Map<String, List<Catalog2Vo>> getCatelogJson() {
        //代码性能优化:先查出所有分类数据,再进行筛选,减少与数据库的交互,进而提高性能
        List<CategoryEntity> all = this.baseMapper.selectList(new LambdaQueryWrapper<CategoryEntity>());
        if(all == null){
            return null;
        }

        //1.先查出所有的一级分类
        List<CategoryEntity> level1Category = getLevel1Category();
        //2.封装
        Map<String, List<Catalog2Vo>> map = level1Category.stream().collect(Collectors.toMap(k -> k.getCatId().toString(), v -> {
            //2.1查出二级分类
            List<CategoryEntity> catelog2List = all.stream().filter(i -> i.getParentCid().longValue() == v.getCatId().longValue()).collect(Collectors.toList());
//            List catelog2List = this.baseMapper.selectList(new LambdaQueryWrapper().eq(CategoryEntity::getParentCid, v.getCatId()));

            List<Catalog2Vo> collect = null;
            if(null != catelog2List){
                collect = catelog2List.stream().map(i -> {
                    //3.1查出三级分类
                    List<CategoryEntity> catelog3List = all.stream().filter(e -> e.getParentCid().longValue() == i.getCatId().longValue()).collect(Collectors.toList());
//                    List catelog3List = this.baseMapper.selectList(new LambdaQueryWrapper().eq(CategoryEntity::getParentCid, i.getCatId()));
                    List<Catalog2Vo.Catalog3Vo> catelog3Vos = null;
                    if(null != catelog3List){
                        catelog3Vos = catelog3List.stream().map(j -> {
                            Catalog2Vo.Catalog3Vo catelog3Vo = new Catalog2Vo.Catalog3Vo();
                            catelog3Vo.setCatalog2Id(i.getCatId().toString());
                            catelog3Vo.setId(j.getCatId().toString());
                            catelog3Vo.setName(j.getName());
                            return catelog3Vo;
                        }).collect(Collectors.toList());
                    }
                    Catalog2Vo catalog2Vo = new Catalog2Vo();
                    catalog2Vo.setCatalog1Id(v.getCatId().toString());
                    catalog2Vo.setCatalog3List(catelog3Vos);
                    catalog2Vo.setId(i.getCatId().toString());
                    catalog2Vo.setName(i.getName());
                    return catalog2Vo;
                }).collect(Collectors.toList());
            }

            return collect;
        }));
        return map;
    }

再见

你可能感兴趣的:(redis,缓存,redisson,spring,boot,java)