springboot-redis缓存数据信息

springboot-redis+spring-cache缓存数据信息

新手笔记,狂神搬运工
**本篇依据狂神瑞吉外卖项目缓存短信,菜品数据部分进行记录

狂神说Java

redis配置

依赖导入

        <!--redis-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
       <!--redis依赖的连接池-->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-pool2</artifactId>
        </dependency>

yaml配置redis

server:
  port: 8080
spring:
  redis:
    database: 0  #操作0号数据库
    host: 127.0.0.1
    port: 6379
    password: '123456'
    lettuce:
      pool:
        max-active: 8
        max-idle: 8
        min-idle: 0
        max-wait: 100ms

##rediscofig配置(主要是为了redis图形化界面便于查看数据)

package com.itheima.reggie.config;

import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;

/**
 * Redis配置类
 */

@Configuration
public class RedisConfig extends CachingConfigurerSupport {

    @Bean
    public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory connectionFactory) {

        RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();

        //默认的Key序列化器为:JdkSerializationRedisSerializer
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());

        redisTemplate.setConnectionFactory(connectionFactory);

        return redisTemplate;
    }

}

缓存短信验证码

在未优化的项目中,验证码存储在session中,有效期(30min),我们需要将其缓存在redis中:

//先注入redistenmplate
    @Autowired
    private RedisTemplate redisTemplate;

//在发送验证码的方法中修改,将验证码存在redis中
//设置有效期为5分钟,将phone设置为key
redisTemplate.opsForValue().set(phone,code,5, TimeUnit.MINUTES);

//在登陆方法中
//从redis中获取缓存的验证码
Object codeInSession=redisTemplate.opsForValue().get(phone);
//用户登陆成功,删除redis中缓存的验证码
   redisTemplate.delete(phone);

缓存菜品数据

缓存菜品数据

在移动端,用户查询某个菜品分类时都要查询数据库,造成频繁访问,极大的降低了性能,所以需要将菜品数据存放在缓存中,避免频繁访问数据库。
思路:先从redis中获取菜品数据,如果有则直接返回,不需要查询数据库,如果没有则查询数据库,并将查询到的数据放入redis。
改造菜品新增和更新方法,加入清理缓存逻辑。
(缓存使用中要注意保证数据库中的数据和缓存中的数据的一致性,数据库中的数据发生变化时,要及时清理缓存数据)

//在dishcontroller中先注入redistemplate
    @Autowired
    private RedisTemplate redisTemplate;


 //在获取菜品数据方法中添加缓存
   @GetMapping("/list")
    public R<List<DishDto>> list(Dish dish)
    {
        List<DishDto> dishDtoList=null;
        //动态构造key
        String key="dish_"+dish.getCategoryId()+"_"+dish.getStatus();

        //先从redis中获取缓存数据
        dishDtoList= (List<DishDto>) redisTemplate.opsForValue().get(key);

        if(dishDtoList!=null)
        {
            //如果存在直接返回,不需要查询数据库
            return R.success(dishDtoList);

        }


        //如果不存在,需要查询数据库,查询出的菜品数据缓存到redis

        //构造查询条件
        LambdaQueryWrapper<Dish> queryWrapper=new LambdaQueryWrapper<>();
        queryWrapper.eq(dish.getCategoryId()!=null,Dish::getCategoryId,dish.getCategoryId());
        queryWrapper.eq(Dish::getStatus,1 );
        //添加排序条件
        queryWrapper.orderByAsc(Dish::getSort).orderByDesc(Dish::getUpdateTime);

        List<Dish> list = dishService.list(queryWrapper);
           dishDtoList=list.stream().map((item)->{
            DishDto dishDto=new DishDto();
            //使用对象拷贝给dishdto的普通属性赋值
            BeanUtils.copyProperties(item,dishDto);

            Long categoryId = item.getCategoryId();//分类id
            //根据id查询分类对象
            Category category = categoryService.getById(categoryId);
            if(category!=null)
            {
                String name1 = category.getName();
                dishDto.setCategoryName(name1);
            }
            Long dishId = item.getId();//菜品id
            LambdaQueryWrapper<DishFlavor> lambdaQueryWrapper=new LambdaQueryWrapper<>();
            lambdaQueryWrapper.eq(DishFlavor::getDishId,dishId);
            List<DishFlavor> dishFlavorList = dishFlavorService.list(lambdaQueryWrapper);
            dishDto.setFlavors(dishFlavorList);
            return dishDto;
        }).collect(Collectors.toList());

           //缓存到redis
           redisTemplate.opsForValue().set(key,dishDtoList,60, TimeUnit.MINUTES);
        return R.success(dishDtoList);
    }


清理缓存

错误分析:
当增加一个菜品后,再次查询菜品会发现看不到新增的菜品,因为在新增菜品前缓存没有清理,新增菜品后,再次查询数据并不会查询数据库,而是查询旧的缓存,导致出错。修改菜品同样也会出现这种错误。
在清理缓存时可以清理掉全部缓存(数据较少时),也可以精确清理。
修改菜品缓存清理:

   @PutMapping
    public R<String> update(@RequestBody DishDto dishDto)//前端传回的json数据由requestbody反序列化到实体对象中
    {
        log.info(dishDto.toString());
        dishService.updateWithFlavor(dishDto);

        //清理所有菜品缓存
//        Set keys = redisTemplate.keys("dish_*");
//        redisTemplate.delete(keys);
        //清理某个分类下面的菜品缓存,构造key
        String key="dish_"+dishDto.getCategoryId()+"_1";
        redisTemplate.delete(key);

        return R.success("修改菜品成功");
    }

新增菜品的缓存修改同理

spring cache简介

spring Cache是一个框架,实现了基于注解的缓存功能,只需要简单地加一个注解就能实现缓存功能。
它提供了一层抽象,底层可以切换不同的cahce实现,具体是通过Cachemanger接口来统一不同的缓存技术.
Cachemanger是Spring提供的各种缓存技术抽象接口。通过它就不需要自己编写缓存逻辑了,只需要开启相应注解即可。
在这里插入图片描述

spring cache常用注解

在这里插入图片描述
在项目中导入spring-boot-starter-web其实已经可以使用spring-cache的基础功能了(jar包在spring-context上下文配置中),在使用时首先在对应controller下注入manager注解

    @Autowired
    private CacheManager cacheManager;

重要的是要在启动类上加上开启缓存注解
@EnableCaching
之后就可以在对应controller下使用缓存注解了:
1、@CachePut注解
可以使用CachePut注解将方法返回值放回缓存

   @CachePut(value = "缓存的名称",key = "缓存的key(#xxx)")

每个缓存名称下可以有多个key,而这里的key是个动态的key(具有该缓存的标识),例如 #user.id(使用id作为缓存的key, spel表达式)
2、@CacheEvict注解
清理缓存数据

   @CacheEvict(value = "缓存的名称",key = "缓存的key(#xxx)")

3、@Cacheable注解
该注解作用是:在方法执行前spring先查看缓存中是否有数据,如果有数据,则直接返回缓存数据;若没有数据,调用方法并将方法返回值放到缓存中
value:缓存的名称,每个缓存名称下面可以有多个key
key:缓存的key
condition:条件,满足条件是才缓存数据
unless:满足条件则不缓存

spring cache-使用redis作为缓存产品

首先需要导入相应的坐标

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

配置yaml文件

  redis:
    database: 0  #操作0号数据库
    host: 127.0.0.1
    port: 6379
    password: '123456'
    lettuce:
      pool:
        max-active: 8
        max-idle: 8
        min-idle: 0
        max-wait: 100ms
  cache:
    redis:
      time-to-live: 1800000 #设置过期时间

对套餐信息进行缓存

实现思路:
1、导入Spring Cache和Redis相关maven坐标
2、在application.yml中配置缓存数据的过期时间
3、在启动类上加入@EnableCaching注解,开启缓存注解功能
4、在SetmealController的list方法上加入@Cacheable注解
5、在SetmealController的save和delete方法上加入CacheEvict注解
前三步已经完成了,现在进行注解配置:

/**
     * 根据条件查询套餐数据
     * @param setmeal
     * @return
     */
      @Cacheable(value = "setmealCache",key = "#setmeal.categoryId+'_'+#setmeal.status")
      @GetMapping("/list")
      public R<List<Setmeal>>list(Setmeal setmeal)
      {
          LambdaQueryWrapper<Setmeal> queryWrapper =new LambdaQueryWrapper<>();
          queryWrapper.eq(setmeal.getCategoryId()!=null,Setmeal ::getCategoryId,setmeal.getCategoryId());
          queryWrapper.eq(setmeal.getStatus()!=null,Setmeal::getStatus,setmeal.getStatus());
          queryWrapper.orderByDesc(Setmeal::getUpdateTime);
          List<Setmeal> list = setmealService.list(queryWrapper);
          return  R.success(list);
      }

这里需要为返回的R实现序列化接口


/**
 * 通用返回结果类,服务端响应的数据最终会封装成此类对象
 * @param <T>
 */
@Data
public class R<T> implements Serializable {

    private Integer code; //编码:1成功,0和其它数字为失败

    private String msg; //错误信息

    private T data; //数据

    private Map map = new HashMap(); //动态数据

    public static <T> R<T> success(T object) {
        R<T> r = new R<T>();
        r.data = object;
        r.code = 1;
        return r;
    }

    public static <T> R<T> error(String msg) {
        R r = new R();
        r.msg = msg;
        r.code = 0;
        return r;
    }

    public R<T> add(String key, Object value) {
        this.map.put(key, value);
        return this;
    }

}

缓存配置:

//删除套餐加上如下注解,allEntries 为true表示删除所有缓存:
 @CacheEvict(value = "setmealCache",allEntries = true)

新增,修改套餐同理

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值