首页 > 其他分享 >缓存优化

缓存优化

时间:2023-06-24 15:32:23浏览次数:35  
标签:缓存 key org y1 import 优化 id

前言:

经过前面linux,redis,git的学习介绍,我们至此进入项目优化阶段

1. 项目问题  1-1

用户数量多,系统访问量大

频繁访问数据库,系统性能下降,用户体验差

缓存优化_缓存

2. 环境搭建  1-2

将我们的项目推送远程仓库   1-2

缓存优化_验证码_02

在创建一个新的分支,在次分支上进行项目优化

缓存优化_验证码_03

缓存优化_spring cache_04

将v1.0 分支也推送远程仓库

缓存优化_缓存_05

缓存优化_spring cache_06

2.1 maven 坐标   1-3

在项目的pom. xml文件中导入spring data redis 的maven坐标: 

pom.xml

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

在项目的application. yml中加入redis相关配置:

application.yml 

spring:
   redis:
    host: localhost
    port: 6379
    #password: 123456
    database: 0 #操作的是0号数据库

redis序列化器  RedisConfig  1-3

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序列化器   1-3
@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.setConnectionFactory(connectionFactory);
        return redisTemplate;
    }
}

接着添加,提交

缓存优化_验证码_07

缓存优化_redis_08

推送成功

缓存优化_redis_09

3. 缓存短信验证码   1-4

3.1 实现思路

前面我们已经实现了移动端手机验证码登录,随机生成的验证码我们是保存在HttpSession中的。现在需要改造为将验证码缓存在Redis中,具体的实现思路如下:

1、在服务端UserController中注入RedisTemplate对象,用于操作Redis

2、在服务端UserController的sendMsg方法中,将随机生成的验证码缓存到Redis中,并设置有效期为5分钟

3、在服务端UserController的login方法中,从Redis中获取缓存的验证码,如果登录成功则删除Redis中的验证码

3.2 代码改造  1-4

UserController

//注入redisTemplate对象    优化1-4
    @Autowired
    private RedisTemplate redisTemplate;

获取手机验证码  优化  sendMsg   优1-4

//获取手机验证码  优化1-4
    @PostMapping("/sendMsg")
    public R<String> sendMsg(@RequestBody User user,HttpSession session){

        //获取手机号
        String phone = user.getPhone();
        if(StringUtils.isNotEmpty(phone)){//手机号不为空
            //生成随机的4为验证码
            String code = ValidateCodeUtils.generateValidateCode(4).toString();
            log.info("code={}",code);

            //调用阿里云提供的短信服务AP完成发送短信
            //SMSUtils.sendMessage("瑞吉外卖","",phone,code);
            //需要将验证码保存到session
            //session.setAttribute(phone,code);

            //将生成的验证码缓存到Redis中,并且设置有效期为5分钟    优1-4
            redisTemplate.opsForValue().set(phone,code,5, TimeUnit.MINUTES);

            return R.success("手机验证码发送成功");
        }

        return R.error("短信发送失败");
    }

移动端用户登录 优化     login  优1-4

/**
     * 移动端用户登录 优化   优1-4
     * @param map
     * @param session
     * @return
     */
    @PostMapping("/login")
    public R<User> login(@RequestBody Map map, HttpSession session){
        log.info(map.toString());

        //获取手机号
        String phone = map.get("phone").toString();

        //获取验证码
        String code = map.get("code").toString();

        //从Session中获取保存的验证码
        //Object codeInSession = session.getAttribute(phone);

        //从redis中获取缓存的验证码  优1-4
        Object codeInSession = redisTemplate.opsForValue().get(phone);

        //进行验证码的比对(页面提交的验证码和Session中保存的验证码比对)
        if(codeInSession != null && codeInSession.equals(code)){
            //如果能够比对成功,说明登录成功

            //判断当前手机号对应的用户是否为新用户,如果是新用户就自动完成注册
            LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
            //构造查询条件,将手机号作为查询条件
            queryWrapper.eq(User::getPhone,phone);

            User user = userService.getOne(queryWrapper);
            if(user == null){
                //是新用户就自动完成注册
                user = new User();
                user.setPhone(phone);
                user.setStatus(1);
                userService.save(user);
            }

            //将用户id放入session
            session.setAttribute("user",user.getId());

            //如果用户登录成功,删除Redis中缓存的验证码   优1-4
            redisTemplate.delete(phone);

            return R.success(user);
        }
        return R.error("登录失败");
    }

3.3 测试   1-4

运行程序

缓存优化_验证码_10

查看redis

缓存优化_缓存_11

登录成功

缓存优化_验证码_12

再次查看redis

缓存优化_spring cache_13

ps 还可以使用redis图形化界面

E:\java\tools\Redis\ziliao\redisclient-win32.x86_64.2.0.jar   :    Redis图形界面客户端

执行方式: 在这个文件所在的目录cmd,  执行 java -jar redisclient-win32.x86_64.2.0.jar

缓存优化_redis_14

启动成功后,点击左上角的Server---add 

缓存优化_spring cache_15

缓存优化_spring cache_16

发送验证码,redis里出现手机号

缓存优化_缓存_17

登录成功后手机号被删除

缓存优化_缓存_18

4. 缓存菜品数据   1-5

4.1 实现思路  1-5

前面我们已经实现了移动端菜品查看功能T对应的服务端方法为DishController的list方法,此方法会根据前端提交的查询条件进行数据库查询操作。在高并发的情况下,频繁查询数据库会导致系统性能下降,服务端响应时间增长。现在需要对此方法进行缓存优化,提高系统的性能。具体的实现思路如下:

1、改造DishController的list方法,先从Redis中获取菜品数据,如果有则直接返回,无需查询数据库;如果没有则查询数据库,并将查询到的菜品数据放入Redis。

2、改造DishController的save和update方法, 加入清理缓存的逻辑

缓存优化_spring cache_19

4.2 代码实现   1-6

DishController

//注入redisTemplate对象    优化1-6
    @Autowired
    private RedisTemplate redisTemplate;

根据菜品分类的id查询菜品改造  优化  list

//根据菜品分类的id查询菜品改造  优化  优1-6
    @GetMapping("/list")
    public R<List<DishDto>> list(Dish dish){

        List<DishDto> dishDtoList = null;

        //动态构造key,使用分类的id和售卖状态可以保证唯一性
        //dish_1397844391040167938_1
        String key = "dish_" + dish.getCategoryId() + "_" + dish.getStatus();

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

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

        //构造查询条件对象
        LambdaQueryWrapper<Dish> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(dish.getCategoryId()!=null,Dish::getCategoryId,dish.getCategoryId());
        //添加条件,查询状态为1的也就是起售的菜品
        queryWrapper.eq(Dish::getStatus,1);

        //添加排序条件
        queryWrapper.orderByAsc(Dish::getSort).orderByDesc(Dish::getUpdateTime);

        List<Dish> list = dishService.list(queryWrapper);

        //遍历list集合
        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 categoryName = category.getName();
                dishDto.setCategoryName(categoryName);
            }

            //设置菜品口味
            Long id = item.getId();
            LambdaQueryWrapper<DishFlavor> dishFlavorLambdaQueryWrapper = new LambdaQueryWrapper<>();
            dishFlavorLambdaQueryWrapper.eq(DishFlavor::getDishId,id);
            List<DishFlavor> dishFlavorList = dishFlavorService.list(dishFlavorLambdaQueryWrapper);

            dishDto.setFlavors(dishFlavorList);

            return dishDto;

        }).collect(Collectors.toList());

        //如果不存在,需要查询数据库,将查询到的菜品数据缓存到Redis
        //这里解释opsForValue不是村String类型的嘛,为啥可以存list
        //opsForValue()是操作String类型数据的方法,但是可以通过一些转
        //换操作,将List类型的元素转换为字符串进行存储,比如序列化操作或转换为JSON格式再存储。
        //在读取时,我们也需要将其转换为List类型,但是在读取时需要进行一些转换操作,
        // 并且这种方式不能很好地支持对List中的元素进行增删改查等操作。因此,在某些情况下,
        // 建议使用Redis中专门的List数据结构来存储List类型的数据,以获得更好的性能和支持更多的操作方式。
        redisTemplate.opsForValue().set(key,dishDtoList,60, TimeUnit.MINUTES);

        return R.success(dishDtoList);
    }

4.2.1 测试  1-6

运行登录,果然在redis中发现了菜品缓存

缓存优化_spring cache_20

4.3 更改save和update  1-7

修改菜品 优化  update   1-7

更新菜品我们采取,删除redis中所有以dish_开头的key方法,简单粗暴

//修改菜品 优化  优1-7
    @PutMapping
    public R<String> update(@RequestBody DishDto dishDto){
        log.info(dishDto.toString());

        //调用我们自己实现的方法因为DishDto中包含了dish_flavor表
        dishService.updateWithFlavor(dishDto);

        //清理所有的菜品的缓存数据
        Set keys = redisTemplate.keys("dish_*");
        redisTemplate.delete(keys);


        return R.success("新增菜品成功");
    }

测试更新菜品,发现更新前菜品缓存还在,更新某一个菜品后,所有的菜品缓存被删除

缓存优化_缓存_21

缓存优化_spring cache_22

我们再采用精确处理的方法,指清理某个特定被更新的菜品缓存

//修改菜品 优化  优1-7
    @PutMapping
    public R<String> update(@RequestBody DishDto dishDto){
        log.info(dishDto.toString());

        //调用我们自己实现的方法因为DishDto中包含了dish_flavor表
        dishService.updateWithFlavor(dishDto);

        //清理所有的菜品的缓存数据   y1-7
//        Set keys = redisTemplate.keys("dish_*");
//        redisTemplate.delete(keys);

        //清理某个分类下面的菜品缓存数据   y1-7
        //思路就在于我们需要知道被更新菜品缓存的key是多少
        String key = "dish_" + dishDto.getCategoryId() + "_1";
        redisTemplate.delete(key);


        return R.success("新增菜品成功");
    }

再更新前缓存优4条,更新后剩下3条,说明我们只删除了被更新菜品的缓存

缓存优化_缓存_23

缓存优化_redis_24

新增菜品   save 优化  y1-7

/**
     * 新增菜品 优化  y1-7
     * @param dishDto
     * @return
     */
    @PostMapping
    public R save(@RequestBody DishDto dishDto){
        log.info(dishDto.toString());

        //调用我们自己在DishServiceImpl实现的方法   4-11
        //我们在DishServiceImpl业务层中自己实现数据保存(因为涉及两张
        // 表操作框架无法为我们提供合适的方法)
        dishService.saveWithFlavor(dishDto);

        //清理所有的菜品的缓存数据   y1-7
//        Set keys = redisTemplate.keys("dish_*");
//        redisTemplate.delete(keys);

        //清理某个分类下面的菜品缓存数据   y1-7
        //思路就在于我们需要知道被更新菜品缓存的key是多少
        String key = "dish_" + dishDto.getCategoryId() + "_1";
        redisTemplate.delete(key);

        return R.success("新增菜品成功");
    }

和更新菜品一样的套路,新增前3条,新增后2条

缓存优化_验证码_25

缓存优化_spring cache_26

4.4 提交远程 并合并主分支 1-8

提交

缓存优化_缓存_27

缓存优化_验证码_28

合并

切回主分支

缓存优化_缓存_29

点击右下角master

缓存优化_redis_30

查看代码合并成功,因为出现了我们注释的代码

缓存优化_redis_31

5. Spring Cache   1-9

5.1 spring cache介绍   1-9

Spring Cache是一个框架,实现了基于注解的缓存功能,只需要简单地加一-个注解,就能实现缓存功能。

Spring Cache提供了一层抽象,底层可以切换不同的cache实现。具体就是通过CacheManager接口来统一不同的缓存技术。

CacheManager是Spring提供的各种缓存技术抽象接口。

针对不同的缓存技术需要实现不同的CacheManager: 

缓存优化_验证码_32

5.2 spring cahche常用注解   y1-9

缓存优化_redis_33

在spring boot项目中,使用缓存技术只需在项目中导入相关缓存技术的依赖包,并在启动类.上使用@EnableCaching开启缓存支持即可。

例如,使用Redis作为缓存技术,只需要导入Spring data Redis的maven坐标即可。

5.3 spring cache 使用方法    y1-10

项目在E:\java学习\瑞吉外卖\course2\cache_demo

新建数据库

缓存优化_redis_34

缓存优化_spring cache_35

缓存优化_验证码_36

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.4.5</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.itheima</groupId>
    <artifactId>cache_demo</artifactId>
    <version>1.0-SNAPSHOT</version>
    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.20</version>
        </dependency>

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.76</version>
        </dependency>

        <dependency>
            <groupId>commons-lang</groupId>
            <artifactId>commons-lang</artifactId>
            <version>2.6</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-cache</artifactId>
        </dependency>

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

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>

        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.4.2</version>
        </dependency>

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.1.23</version>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>2.4.5</version>
            </plugin>
        </plugins>
    </build>
</project>

applicationg.yml

server:
  port: 8080
spring:
  application:
    #应用的名称,可选
    name: cache_demo
  datasource:
    druid:
      driver-class-name: com.mysql.cj.jdbc.Driver
      url: jdbc:mysql://localhost:3306/cache_demo?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&useSSL=false&allowPublicKeyRetrieval=true
      username: root
      password: lzl
mybatis-plus:
  configuration:
    #在映射实体或者属性时,将数据库中表名和字段名中的下划线去掉,按照驼峰命名法映射
    map-underscore-to-camel-case: true
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
  global-config:
    db-config:
      id-type: ASSIGN_ID

实体类User

package com.itheima.entity;

import lombok.Data;
import java.io.Serializable;

@Data
public class User implements Serializable {

    private static final long serialVersionUID = 1L;

    private Long id;

    private String name;

    private int age;

    private String address;

}

持久层接口UserMapper

package com.itheima.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.itheima.entity.User;
import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface UserMapper extends BaseMapper<User>{
}

业务层接口  UserService

package com.itheima.service;

import com.baomidou.mybatisplus.extension.service.IService;
import com.itheima.entity.User;

public interface UserService extends IService<User> {
}

业务层接口实现类  UserServiceImpl

package com.itheima.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.itheima.entity.User;
import com.itheima.mapper.UserMapper;
import com.itheima.service.UserService;
import org.springframework.stereotype.Service;

@Service
public class UserServiceImpl extends ServiceImpl<UserMapper,User> implements UserService {
}

启动类CacheDemoApplication

package com.itheima;

import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;

@Slf4j
@SpringBootApplication
@EnableCaching  //开启缓存注解的功能  y1-10
public class CacheDemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(CacheDemoApplication.class,args);
        log.info("项目启动成功...");
    }
}

控制层 UserController

package com.itheima.controller;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.itheima.entity.User;
import com.itheima.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.web.bind.annotation.*;
import java.util.ArrayList;
import java.util.List;


//y1-10
@RestController
@RequestMapping("/user")
@Slf4j
public class UserController {

    @Autowired
    private CacheManager cacheManager;

    @Autowired
    private UserService userService;

}

5.3.1  保存方法 CachePut:将方法返回值放入缓存   y1-10

/**
     * CachePut:将方法返回值放入缓存   y1-10
     * value:缓存的名称,每个缓存名称下面可以有多个key
     * key:缓存的key
     */
    @CachePut(value = "userCache",key = "#user.id")
    @PostMapping
    public User save(User user){
        userService.save(user);
        return user;
    }

使用postman进行测试

缓存优化_验证码_37

数据库插入数据成功

缓存优化_redis_38

通过debug查看缓存数据查看缓存成功

缓存优化_验证码_39

5.3.2 删除方法 CacheEvict:清理指定缓存   y1-11

/**
     * CacheEvict:清理指定缓存   y1-11
     * value:缓存的名称,每个缓存名称下面可以有多个key
     * key:缓存的key
     */
    @CacheEvict(value = "userCache",key = "#p0")
    //@CacheEvict(value = "userCache",key = "#root.args[0]")
    //@CacheEvict(value = "userCache",key = "#id")
    @DeleteMapping("/{id}")
    public void delete(@PathVariable Long id){
        userService.removeById(id);
    }

测试

现在缓存中存入a,b

缓存优化_redis_40

缓存优化_缓存_41

现在删除a的缓存,但是我们在操作之前先存入c的缓存,以便区分

缓存中只剩b了,成功

缓存优化_缓存_42

5.3.3 更新方法 CacheEvict:清理指定缓存   y1-11

//更新方法  CacheEvict:清理指定缓存   y1-11
    //@CacheEvict(value = "userCache",key = "#p0.id")
    //@CacheEvict(value = "userCache",key = "#user.id")
    //@CacheEvict(value = "userCache",key = "#root.args[0].id")
    @CacheEvict(value = "userCache",key = "#result.id")
    @PutMapping
    public User update(User user){
        userService.updateById(user);
        return user;
    }

测试,我们往缓存中加入d,e,f

缓存优化_spring cache_43

缓存优化_spring cache_44

指定修改d

缓存优化_缓存_45

数据库更新成功

缓存优化_缓存_46

查看缓存,再没更新之前时三条数据,执行之后剩下两条d缓存被删除

缓存优化_spring cache_47

缓存优化_缓存_48

5.3.4 查询方法  Cacheable    y1-12

Cacheable:在方法执行前spring先查看缓存中是否有数据,如果有数据,则直接返回缓存数据;若没有数据,调用方法并将方法返回值放到缓存中

/**
     * Cacheable:在方法执行前spring先查看缓存中是否有数据,如果有数据,则直接返回缓
     * 存数据;若没有数据,调用方法并将方法返回值放到缓存中
     * value:缓存的名称,每个缓存名称下面可以有多个key
     * key:缓存的key
     * condition:条件,满足条件时才缓存数据
     * unless:满足条件则不缓存
     */
    
    //这里解释condition = "#result != null",当返回值不为空时才缓存数据,这是为了防止,我们查不到数据
    //也被缓存产生垃圾数据的现象
    //unless = "#result == null"时当返回值为空时就不缓存,他和condition是正好相反
    //@Cacheable(value = "userCache",key = "#id",condition = "#result != null")
    @Cacheable(value = "userCache",key = "#id",unless = "#result == null")
    @GetMapping("/{id}")
    public User getById(@PathVariable Long id){
        User user = userService.getById(id);
        return user;
    }

测试

缓存优化_spring cache_49

第一次查询了数据库,因为缓存中没有数据

缓存优化_缓存_50

第二次再次查询,不走数据库了,直接走了缓存,因为缓存中有了数据

缓存优化_缓存_51

和上述查询一样的原理,不做测试了

//条件查询,如果id不为空就根据id查,如果name不为空就根据name查,都不为空就一起查    y1-12
    @Cacheable(value = "userCache",key = "#user.id + '_' + #user.name")
    @GetMapping("/list")
    public List<User> list(User user){
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(user.getId() != null,User::getId,user.getId());
        queryWrapper.eq(user.getName() != null,User::getName,user.getName());
        List<User> list = userService.list(queryWrapper);
        return list;
    }

5.4 使用redis缓存  y1-13

缓存优化_验证码_52

pom.xml

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

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

application.yml

缓存优化_缓存_53

server:
  port: 8080
spring:
  application:
    #应用的名称,可选
    name: cache_demo
  datasource:
    druid:
      driver-class-name: com.mysql.cj.jdbc.Driver
      url: jdbc:mysql://localhost:3306/cache_demo?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&useSSL=false&allowPublicKeyRetrieval=true
      username: root
      password: lzl
  #加入redis   y1-13
  redis:
    host: localhost
    port: 6379
    #password: 123456
    #操作的是0号数据库
    database: 0
  cache:
    redis:
      time-to-live: 1800000 #设置缓存数据的过期时间
mybatis-plus:
  configuration:
    #在映射实体或者属性时,将数据库中表名和字段名中的下划线去掉,按照驼峰命名法映射
    map-underscore-to-camel-case: true
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
  global-config:
    db-config:
      id-type: ASSIGN_ID

测试查询方法

@Cacheable(value = "userCache",key = "#id",unless = "#result == null")
    @GetMapping("/{id}")
    public User getById(@PathVariable Long id){
        User user = userService.getById(id);
        return user;
    }

测试缓存成功

缓存优化_验证码_54

6. 缓存套餐数据 y1-14

6.1 实现思路

前面我们已经实现了移动端套餐查看功能,对应的服务端方法为SetmealController的list方法,此方法会根据前端提交的查询条件进行数据库查询操作。在高并发的情况下,频繁查询数据库会导致系统性能下降,服务端响应时间增长。现在需要对此方法进行缓存优化,提高系统的性能。

具体的实现思路如下:

1、导入Spring Cache和Redis相关maven坐标.

2、在application.yml中 配置缓存数据的过期时间

3、在启动类上加入@EnableCaching注解,开启缓存注解功能

4、在SetmealController的list方法上加入@Cacheable注解

5、在SetmealController的save和delete方法.上加入CacheEvict注解

6.2 代码实现    y1-14

导入Spring Cache和Redis相关maven坐标.

pom.xml

<!--redis依赖   y1-3-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

<!--spring cache依赖  y1-14-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-cache</artifactId>
</dependency>

在application.yml中 配置缓存数据的过期时间    y1-14

缓存优化_缓存_55

application.yml

cache:
    redis:
      time-to-live: 1800000 #设置缓存数据的过期时间

在启动类上加入@EnableCaching注解,开启缓存注解功能   y1-14

ReggieApplication

package com.itheima.reggie;

import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.transaction.annotation.EnableTransactionManagement;

//启动类  5
@Slf4j  //这个注解是lombok提供的 日志文件
@SpringBootApplication
@ServletComponentScan //目的是让我们定义的过滤器生效
@EnableTransactionManagement  //使我们的事务注解起作用  4-10
@EnableCaching //开启spring Cache
public class ReggieApplication {
    public static void main(String[] args) {
        SpringApplication.run(ReggieApplication.class,args);
        log.info("项目启动成功。。。。!!!***~####");
    }
}

在SetmealController的list方法上加入@Cacheable注解   y1-14

SetmealController

/**
     * 根据条件查询套餐数据优化  y1-14
     * @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>而R是我们自己定义的,没有序列化,需要将其继承序列化接口

缓存优化_spring cache_56

缓存优化_缓存_57

改造R

缓存优化_验证码_58

再次重启测试

正常展示

缓存优化_spring cache_59

查看缓存

缓存优化_缓存_60

在SetmealController的save和delete方法.上加入CacheEvict注解 y1-14

SetmealController

//新增套餐  优化  y1-14
    @CacheEvict(value = "setmealCache",allEntries = true)
    @PostMapping
    public R<String> save(@RequestBody SetmealDto setmealDto){
        log.info("套餐信息 {}",setmealDto);

        setmealService.saveWithDish(setmealDto);

        return R.success("新增套餐成功");
    }
 /**
     * 删除套餐  优化  y1-14
     * @param ids
     * @return
     */
    //allEntries = true 表示删除setmealCache底下的所有缓存数据
    @CacheEvict(value = "setmealCache",allEntries = true)
    @DeleteMapping
    public R<String> delete(@RequestParam List<Long> ids){
        log.info("ids:{}",ids);

        setmealService.removeWithDish(ids);

        return R.success("套餐数据删除成功");
    }

测试再新增之前套餐缓存还在,新增之后就没了

缓存优化_redis_61

缓存优化_redis_62

新增的套餐

缓存优化_验证码_63

6.3 提交代码和合并  y1-15

提交

缓存优化_缓存_64

缓存优化_验证码_65

合并  y1-15

切换回master,然后合并

缓存优化_验证码_66

随便找一个修改过的代码,合并成功

缓存优化_缓存_67

标签:缓存,key,org,y1,import,优化,id
From: https://blog.51cto.com/u_15784725/6541195

相关文章

  • ASP.NET Core MVC 从入门到精通之缓存
    随着技术的发展,ASP.NETCoreMVC也推出了好长时间,经过不断的版本更新迭代,已经越来越完善,本系列文章主要讲解ASP.NETCoreMVC开发B/S系统过程中所涉及到的相关内容,适用于初学者,在校毕业生,或其他想从事ASP.NETCoreMVC系统开发的人员。经过前几篇文章的讲解,初步了解ASP.NETCore......
  • [ARM 汇编]高级部分—性能优化与调试—3.4.3 使用模拟器进行调试与测试
    在ARM汇编程序开发过程中,使用模拟器(emulator)进行调试和测试是一种非常有效的方法。模拟器可以在不同的处理器上测试代码,帮助我们发现潜在的问题,并提供丰富的调试功能。本节将介绍如何使用QEMU(一个流行的开源模拟器)进行ARM汇编程序的调试和测试。安装QEMU首先,我们需要安装QEMU......
  • 2023-06-23:redis中什么是缓存击穿?该如何解决?
    2023-06-23:redis中什么是缓存击穿?该如何解决?答案2023-06-23:缓存击穿是指一个缓存中的热点数据非常频繁地被大量并发请求访问,当该热点数据失效的瞬间,持续的大并发请求无法通过缓存获取到数据,而直接访问数据库,这就好像在一个稳固完好的容器上打开了一个洞。解决缓存击穿问题的方......
  • WordPress开启Nginx FastCGI Cache缓存
    本文转载自:WordPress开启NginxFastCGICache缓存更多内容请访问钻芒博客:https://www.zuanmang.netWordPress速度优化始终是一个没有尽头的课题,最近逛几个技术大佬的站点发现都用了Nginx缓存,遂搜集资料展开部署。教程分享如下Ps.由于钻芒博客是通过Nginx反响代理到本地内网访问......
  • WordPress开启Nginx Redis Cache缓存 解决FastCGI Cache内网穿透兼容问题
    本文转载自:WordPress开启NginxRedisCache缓存解决FastCGICache内网穿透兼容问题更多内容请访问钻芒博客:https://www.zuanmang.net上回说到,Wordpress配合NginxFastCGICache缓存可以极大提升速度体验,但钻芒博客由于是通过Nginx反向代理所以使用起来纯在一定兼容问题,比如缓......
  • mongodb 深度分页优化思路之cursor游标
    mongodb没有官方的游标滚动实现深度分页功能,建议的都是选择出一个字段,如_id,然后每次查询时限制该字段,而不进行分页处理。也没有看到更优的实现方式,本文做一个大胆的假设,自行实现滚动分页功能。供大家思路参考。但是猜想可以自行实现一个,简单思路就是,第一次查询时......
  • Java基础之基本数据类型封装类的缓存
    巨人的肩膀:https://blog.csdn.net/hnjcxy/article/details/1237872091、Java中基本数据类型byte、short、char、int、long、float、double、boolean有对应的封装类型:Byte、Short、Character、Integer、long、Float、Double,Boolean其中Byte、Short、Character、Integer、Long、Bo......
  • mysql的IN查询优化
    mysql的IN里面的数量太大,比如大于1千时,查询的性能就会差很多。有以下的解决方法。解决方法一:拆分IN的数量IN数量超过1千,就拆成多条sql,每条sql的IN数量不超过1千。用OR或者UNION进行SQL改写。也可以使用Java写代码,把IN数量进行拆分,每条sql的IN数量不超过1千。多次执行。......
  • 搜索引擎如何优化
    1、了解搜索引擎如何抓取网页和如何索引网页。2、Meta标签优化。3、如何选取关键词并在网页中放置关键词。4、了解主要的搜索引擎。5、主要的互联网目录6、按点击付费的搜索引擎。7、搜索引擎登录。8、链接交换和链接广泛度(LinkPopularity)。9、标签的合理使用:标签的语义......
  • 大数据处理新-分布式算法与优化
    本书介绍    计算机是一种机器,可以被指示执行一系列算术或逻辑运算,以执行特定的任务,如解决特定的问题。计算机程序是计算机执行的指令的集合。一个程序解决一个特定问题的基本方法被称为算法,这个问题可以由一系列定义明确、可由计算机实现的指令来确定。因此,算法可以被看作是一......