05_2023_Redis_redis缓存(cache)_基本使用

1,什么是缓存

在这里插入图片描述
数据库发生改变,Redis还没及时更新,那么从缓存内取到的数据就会出错,就是数据一致性问题

2,添加查询商品详情缓存

我们通过这个接口查询到的数据有很多,我们希望在此做个Redis缓存数据,提供查询速度

在这里插入图片描述

2.1 pom文件

<parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.5.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <properties>
        <java.version>1.8</java.version>
    </properties>

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

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

        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>3.8.0</version>
        </dependency>

        <!--Redis依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
            <version>2.3.4.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>

        <dependency>
            <groupId>org.apache.velocity</groupId>
            <artifactId>velocity-engine-core</artifactId>
            <version>2.1</version>
        </dependency>
        <!--逆向工程需要模板引擎-->
        <dependency>
            <groupId>org.freemarker</groupId>
            <artifactId>freemarker</artifactId>
            <version>2.3.28</version>
        </dependency>

        <dependency>
            <groupId>org.apache.velocity</groupId>
            <artifactId>velocity-engine-core</artifactId>
            <version>2.2</version>
        </dependency>

        <!-- mybatis-plus -->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <!--<version>3.0.5</version>-->
            <version>3.5.1</version>
        </dependency>

        <!-- 代码自动生成器依赖-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-generator</artifactId>
            <version>3.5.1</version>
        </dependency>

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

        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.7.21</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

2.2 配置文件

server:
  port: 18083

spring:
  application:
    name: springboot_redis_cache
  datasource:
    type: com.zaxxer.hikari.HikariDataSource
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://127.0.0.1:3306/java_pro?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&serverTimezone=UTC
    username: root
    password: Root-123
  redis:
    host: 127.0.0.1
    port: 6379
    database: 0
    lettuce:
      pool:
        max-active: 8 #最大连接数
        max-idle: 8 #最大空闲连接
        min-idle: 0 #最小空闲连接
        #连接等待时间
        max-wait: 100

mybatis-plus:
  type-aliases-package: com.study.pojo
  mapper-locations: classpath:mapper/*Mapper.xml

mybatis:
  type-aliases-package: com.study.pojo
  mapper-locations: classpath:mapper/*Mapper.xml

2.3 启动类

package com.study;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
@MapperScan("com.study.mapper")
public class RedisCacheApplication {
    public static void main(String[] args) {
        SpringApplication.run(RedisCacheApplication.class, args);
    }
}

2.4 完成公共类

  • ResponseResult
package com.study.common;


import lombok.Data;

import java.io.Serializable;


@Data
public class ResponseResult<T> implements Serializable {
    private Boolean success;//是否成功
    private Integer code;//状态码
    private String message;//返回消息
    private T data;

    public ResponseResult() {
    }

    public static <T> ResponseResult<T> ok(){
        ResponseResult<T> responseResult = new ResponseResult<T>();
        responseResult.setSuccess(true);
        responseResult.setCode(ResultCode.SUCCESS);
        responseResult.setMessage("执行成功");
        return responseResult;
    }

    public static <T> ResponseResult<T> ok(T data){
        ResponseResult<T> responseResult = new ResponseResult<T>();
        responseResult.setSuccess(true);
        responseResult.setCode(ResultCode.SUCCESS);
        responseResult.setMessage("执行成功");
        responseResult.setData(data);
        return responseResult;
    }

    public static <T> ResponseResult<T> error(Integer code){
        ResponseResult<T> responseResult = new ResponseResult<T>();
        responseResult.setSuccess(false);
        responseResult.setCode(code);
        responseResult.setMessage("执行失败");
        return responseResult;
    }
    public static <T> ResponseResult<T> error(){
        ResponseResult<T> responseResult = new ResponseResult<T>();
        responseResult.setSuccess(false);
        responseResult.setCode(ResultCode.ERROR);
        responseResult.setMessage("执行失败");
        return responseResult;
    }

    public ResponseResult<T> success(Boolean success){
        this.setSuccess(success);
        return this;
    }

    public ResponseResult<T> code (Integer code){
        this.setCode(code);
        return this;
    }

    public ResponseResult<T> message (String message){
        this.setMessage(message);
        return this;
    }

    public static<T> ResponseResult<T> exist (String message){
        ResponseResult<T> responseResult = new ResponseResult<T>();
        responseResult.setSuccess(true);
        responseResult.setCode(ResultCode.SUCCESS);
        responseResult.setMessage(message);
        responseResult.setSuccess(true);
        return responseResult;
    }

    public static<T> ResponseResult<T> exist (){
        ResponseResult<T> responseResult = new ResponseResult<T>();
        responseResult.setSuccess(true);
        responseResult.setCode(ResultCode.SUCCESS);
        responseResult.setSuccess(true);
        return responseResult;
    }
}

  • ResultCode
package com.study.common;

public class ResultCode {
    public static final Integer SUCCESS = 200;
    public static final Integer ERROR = 500;
    public static final int NOT_LOGIN = 600;
    public static final int NOT_AUTH = 700;
}

2.5 完成常量类

package com.study.constants;

public class RedisConstants {
    public static final String LOGIN_CODE_KEY = "login:code:";
    public static final Long LOGIN_CODE_TTL = 10L;
    public static final String LOGIN_USER_KEY = "login:token:";
    public static final Long LOGIN_USER_TTL = 36000L;

    public static final Long CACHE_NULL_TTL = 2L;

    public static final Long CACHE_SHOP_TTL = 30L;
    public static final String CACHE_SHOP_KEY = "cache:shop:";

    public static final String LOCK_SHOP_KEY = "lock:shop:";
    public static final Long LOCK_SHOP_TTL = 10L;

    public static final String SECKILL_STOCK_KEY = "seckill:stock:";
    public static final String BLOG_LIKED_KEY = "blog:liked:";
    public static final String FEED_KEY = "feed:";
    public static final String SHOP_GEO_KEY = "shop:geo:";
    public static final String USER_SIGN_KEY = "sign:";

    public static final String CACHE_SHOPTYPE_KEY = "cache_shoptype_key";
    public static final Long CACHE_SHOPTYPE_TTL = 36000L;
}

2.6 完成代码生成工具

package com.study.utils;


import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.generator.FastAutoGenerator;
import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
import com.baomidou.mybatisplus.generator.config.converts.MySqlTypeConvert;
import com.baomidou.mybatisplus.generator.config.querys.MySqlQuery;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
import com.baomidou.mybatisplus.generator.fill.Column;
import com.baomidou.mybatisplus.generator.keywords.MySqlKeyWordsHandler;

public class MysqlCodeGenerator {

    private static final String URL = "jdbc:mysql://127.0.0.1:3306/java_pro?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&serverTimezone=UTC";
    private static final String username = "root";
    private static final String password = "Root-123";
    private static final String author = "linailong";
    public static void main(String[] args) {
        packMybatisPlus("sys_product");
    }

    static void packMybatisPlus(String table) {
        FastAutoGenerator.create(new DataSourceConfig.Builder(URL, username, password)
                .dbQuery(new MySqlQuery())
                .typeConvert(new MySqlTypeConvert())
                .keyWordsHandler(new MySqlKeyWordsHandler()))
                .globalConfig(builder -> {
                    // 设置作者
                    builder.author("".equals(author) ? System.getProperty("user.name") : author)
                            // 使用java8新的时间类型
                            .dateType(DateType.TIME_PACK)
                            // 指定日期格式化方式
                            .commentDate("yyyy-MM-dd hh:mm:ss")
                            .outputDir("E:\\a_linailong\\myProject\\redis\\Demo03_Redis_Cache\\src\\main\\java");
                })
                .packageConfig(builder -> {
                    // TODO 设置父包名
                    builder.parent("com.study")
                            // 设置父包模块名
//                            .moduleName("system")
                            .entity("pojo")
                            .service("service")
                            .serviceImpl("service.impl")
                            .mapper("mapper")
                            .xml("mapper.xml")
                            .controller("controller");
                })
                .strategyConfig(builder -> {

                    builder
                            // 设置需要生成的表名 不设置表名则生成全部表
                            .addInclude(table)
                            // 开启跳过视图
                            .enableSkipView();

                    // 设置实体类策略
                    builder.entityBuilder()
                            // 开启链式模型
                            .enableChainModel()
                            // 开启lombok
//                            .enableLombok()
                            // 移除boolean的is前缀
                            .enableRemoveIsPrefix()
                            // 从数据库中生成字段注解
                            .enableTableFieldAnnotation()
                            // 命名规则下划线转驼峰
                            .naming(NamingStrategy.underline_to_camel)
                            // 数据库表字段映射到实体的命名策略
                            .columnNaming(NamingStrategy.underline_to_camel)
                            // 设置表字段自动填充
                            .addTableFills(new Column("create_time", FieldFill.INSERT))
                            .addTableFills(new Column("update_time", FieldFill.INSERT_UPDATE));

                    // mapper 生成策略
                    builder.mapperBuilder()
                            // 开启@Mapper注解
                            .enableMapperAnnotation();

                    // service 生成策略
                    builder.serviceBuilder()
                            .formatServiceFileName("%sService")
                            .formatServiceImplFileName("%sServiceImpl");

                    // controller 生成策略
                    builder.controllerBuilder()
                            // 开启驼峰连字符
                            .enableHyphenStyle()
                            // 开始@RestController
                            .enableRestStyle();


                })
                // 使用Freemarker引擎模板,默认的是Velocity引擎模板
                .templateEngine(new FreemarkerTemplateEngine())
                .execute();
    }

}

2.7 完成实体类

package com.study.pojo;

import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;

import java.io.Serializable;

/**
 * <p>
 * 商品表
 * </p>
 *
 * @author linailong
 * @since 2023-02-07 01:59:33
 */
@TableName("sys_product")
@Data
public class SysProduct implements Serializable {

    private static final long serialVersionUID = 1L;

    /**
     * 主键
     */
    @TableId("ID")
    private String id;

    @TableField("`NAME`")
    private String name;

    @TableField("INTRODUCE")
    private String introduce;

    @Override
    public String toString() {
        return "SysProduct{" +
            "id=" + id +
            ", name=" + name +
            ", introduce=" + introduce +
        "}";
    }
}

2.8 完成mapper

package com.study.mapper;

import com.study.pojo.SysProduct;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;

/**
 * <p>
 * 商品表 Mapper 接口
 * </p>
 *
 * @author linailong
 * @since 2023-02-07 01:59:33
 */
@Mapper
public interface SysProductMapper extends BaseMapper<SysProduct> {

}

2.9 完成service以及实现

package com.study.service;

import com.study.common.ResponseResult;
import com.study.pojo.SysProduct;
import com.baomidou.mybatisplus.extension.service.IService;

/**
 * <p>
 * 商品表 服务类
 * </p>
 *
 * @author linailong
 * @since 2023-02-07 01:59:33
 */
public interface SysProductService extends IService<SysProduct> {

    /**
     * 根据id查询商品
     * @param id
     * @return
     */
    ResponseResult getProById(String id);
}

package com.study.service.impl;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.study.common.ResponseResult;
import com.study.constants.RedisConstants;
import com.study.pojo.SysProduct;
import com.study.mapper.SysProductMapper;
import com.study.service.SysProductService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.management.Query;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 * 商品表 服务实现类
 * </p>
 *
 * @author linailong
 * @since 2023-02-07 01:59:33
 */
@Slf4j
@Service
public class SysProductServiceImpl extends ServiceImpl<SysProductMapper, SysProduct> implements SysProductService {
    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Resource
    private SysProductMapper sysProductMapper;

   /**
     * 根据id查询商品
     * @param id
     * @return
     */
    @Override
    public ResponseResult getProById(String id) {
        //1.从Redis内查询商品缓存
        String shopJson = stringRedisTemplate.opsForValue().get(RedisConstants.CACHE_SHOP_KEY + id);
        if(StrUtil.isNotBlank(shopJson)){
            //手动反序列化
            SysProduct pro = JSONUtil.toBean(shopJson, SysProduct.class);
            return ResponseResult.ok(pro);
        }

        //2.不存在就根据id查询数据库
        SysProduct sysProduct = sysProductMapper.selectById(id);
        if(sysProduct==null){
            return ResponseResult.error().message("商品不存在!");
        }

        //3.数据库数据写入Redis
        //手动序列化
        String shopStr = JSONUtil.toJsonStr(sysProduct);
        stringRedisTemplate.opsForValue().set(RedisConstants.CACHE_SHOP_KEY + id,shopStr,RedisConstants.CACHE_SHOP_TTL, TimeUnit.MINUTES);
        return ResponseResult.ok(shopStr);
    }
}

2.10 完成controller

package com.study.controller;


import com.study.common.ResponseResult;
import com.study.pojo.SysProduct;
import com.study.service.SysProductService;
import com.study.service.impl.SysProductServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;

/**
 * <p>
 * 商品表 前端控制器
 * </p>
 *
 * @author linailong
 * @since 2023-02-07 01:59:33
 */
@RestController
@ResponseBody
@RequestMapping("/sysProduct")
public class SysProductController {

    @Resource
    public SysProductService sysProductService;

    /**
     * 根据id查询商品
     */
    @GetMapping("/getProById")
    private ResponseResult getProById(@RequestParam("id") String id){
        return sysProductService.getProById(id);
    }

}

2.11 测试

http://localhost:18083/sysProduct/getProById?id=1
在这里插入图片描述
在这里插入图片描述

3,添加批量查询商品缓存

3.1 完成service以及实现

/**
     * 查询所以商品
     * @return
     */
    ResponseResult getProList();
/**
     * 查询所以商品
     * @return
     */
    @Override
    public ResponseResult getProList() {
        //1.从Redis中查询
        String key = RedisConstants.CACHE_SHOPTYPE_KEY;

        List<String> list = stringRedisTemplate.opsForList().range(key, 0, -1);

        if(!list.isEmpty()){
            //手动反序列化
            List<SysProduct> productList = new ArrayList<>();
            for (String s : list) {
                SysProduct product = JSONUtil.toBean(s, SysProduct.class);
                productList.add(product);
            }
            return ResponseResult.ok(productList);
        }

        //2.从数据库内查询
        QueryWrapper<SysProduct> wrapper = new QueryWrapper<>();
        List<SysProduct> proList = sysProductMapper.selectList(wrapper);
        if(proList.isEmpty()){
            return ResponseResult.error().message("没有商品!");
        }

        //序列化
        for (SysProduct shopType : proList) {
            String s = JSONUtil.toJsonStr(shopType);
            list.add(s);
        }

        //3.存入缓存
        stringRedisTemplate.opsForList().rightPushAll(key,list);
        stringRedisTemplate.expire(key,RedisConstants.CACHE_SHOPTYPE_TTL, TimeUnit.MINUTES);
        return ResponseResult.ok(list);
    }

3.2 完成controller

/**
     * 查询所以商品
     * @return
     */
    @GetMapping("/getProList")
    private ResponseResult getProList(){
        return sysProductService.getProList();
    }

3.3 测试

在这里插入图片描述

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值