文章目录

  • 一、什么是 缓存?
    • ⛅为什么用缓存?
    • ⚡如何使用缓存
  • 二、实现一个商家缓存
    • ⌛环境搭建
    • ♨️核心源码
    • ✅测试接口
  • 三、采用 微服务 Spring Boot 注解开启缓存
    • ✂️@CacheEnable 注解详解
    • ➿调用接口测试
  • ⛵小结

一、什么是 缓存?

缓存(Cache),就是数据交换的缓冲区,俗称的缓存就是缓冲区内的数据,一般从数据库中获取,存储于本地代码,例如:

例1:Static final ConcurrentHashMap<K,V> map = new ConcurrentHashMap<>(); 本地用于高并发例2:static final Cache<K,V> USER_CACHE = CacheBuilder.newBuilder().build(); 用于redis等缓存例3:Static final Map<K,V> map =  new HashMap(); 本地缓存

由于其被Static修饰,所以随着类的加载而被加载到内存之中,作为本地缓存,由于其又被final修饰,所以其引用(例3:map)和对象(例3:new HashMap())之间的关系是固定的,不能改变,因此不用担心赋值(=)导致缓存失效;

⛅为什么用缓存?

一句话总结: 因为使用了缓存后,效率会大大的提升,减少了不必要的资源消耗,提升了用户体验。

但是使用缓存会增加代码复杂度和运维的成本,例如:Redis 集群,多主多从,等等

⚡如何使用缓存

在实际开发中,我们会构建缓存来提升系统的稳定、高可用性,使其性能得到进一步的提升。最常用的是 我们 本地数据与Redis 数据库结合使用

浏览器缓存:主要是存在于浏览器端的缓存

应用层缓存: 可以分为tomcat本地缓存,比如map集合,或者是使用redis作为缓存

数据库缓存: 在数据库中有一片空间是 buffer pool (缓冲池),增改查数据都会先加载到mysql的缓存中

CPU缓存: 当代计算机最大的问题是 cpu性能提升了,但内存读写速度没有跟上,所以为了适应当下的情况,增加了cpu的L1,L2,L3级的缓存

二、实现一个商家缓存

需求说明

本 项目基于 Spring Boot 整合Redis 并引入 MyBatis-Plus 来完成开发

  • 要求达到第一次加载,查询redis缓存是否存在,若不存在,则查询数据库,查询完毕后,存入redis,再次访问时只获取redis缓存中的数据,不必再次加载数据库,减轻数据库压力。

⌛环境搭建

本项目依赖于 3分钟搞懂阿里云服务器部署Reids并整合Spring Boot 微服务项目

数据库 MySQL 8.0

CREATE TABLE `tb_shop` (`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',`name` varchar(128) NOT NULL COMMENT '商铺名称',`type_id` bigint(20) unsigned NOT NULL COMMENT '商铺类型的id',`images` varchar(1024) NOT NULL COMMENT '商铺图片,多个图片以'',''隔开',`area` varchar(128) DEFAULT NULL COMMENT '商圈,例如陆家嘴',`address` varchar(255) NOT NULL COMMENT '地址',`x` double unsigned NOT NULL COMMENT '经度',`y` double unsigned NOT NULL COMMENT '维度',`avg_price` bigint(10) unsigned DEFAULT NULL COMMENT '均价,取整数',`sold` int(10) unsigned zerofill NOT NULL COMMENT '销量',`comments` int(10) unsigned zerofill NOT NULL COMMENT '评论数量',`score` int(2) unsigned zerofill NOT NULL COMMENT '评分,1~5分,乘10保存,避免小数',`open_hours` varchar(32) DEFAULT NULL COMMENT '营业时间,例如 10:00-22:00',`create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',`update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',PRIMARY KEY (`id`) USING BTREE,KEY `foreign_key_type` (`type_id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=15 DEFAULT CHARSET=utf8mb4 ROW_FORMAT=COMPACT

pom依赖

// Mybatis-Plus 核心依赖
<dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.4.3</version>
</dependency>// hutool 工具包,各种封装功能 一应俱全
<dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.8.5</version>
</dependency>

核心配置 application.yaml

server:port: 8082
spring:application:name: easydpdatasource:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://127.0.0.1:3306/db_easy_dp?useSSL=false&serverTimezone=UTCusername: rootpassword: 111111redis:host: redis ip地址port: 6379password: redis密码,如没有不写即可lettuce:pool:max-active: 10max-idle: 10min-idle: 1time-between-eviction-runs: 10sjackson:default-property-inclusion: non_null # JSON处理时忽略非空字段
mybatis-plus:type-aliases-package: com.chen.entity # 别名扫描包
logging:level:com.chen: debug

♨️核心源码

Entity 实体类层

package com.chen.entity;import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;import java.io.Serializable;
import java.time.LocalDateTime;/*** @author whc* @date 2022/9/3 10:29*/
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@TableName("tb_shop")
public class ShopEntity implements Serializable {private static final long serialVersionUID = 1L;/*** 主键*/@TableId(value = "id", type = IdType.AUTO)private Long id;/*** 商铺名称*/private String name;/*** 商铺类型的id*/private Long typeId;/*** 商铺图片,多个图片以','隔开*/private String images;/*** 商圈,例如陆家嘴*/private String area;/*** 地址*/private String address;/*** 经度*/private Double x;/*** 维度*/private Double y;/*** 均价,取整数*/private Long avgPrice;/*** 销量*/private Integer sold;/*** 评论数量*/private Integer comments;/*** 评分,1~5分,乘10保存,避免小数*/private Integer score;/*** 营业时间,例如 10:00-22:00*/private String openHours;/*** 创建时间*/private LocalDateTime createTime;/*** 更新时间*/private LocalDateTime updateTime;@TableField(exist = false)private Double distance;
}

Mapper持久化层

package com.chen.mapper;import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.chen.entity.ShopEntity;/*** @author whc* @date 2022/9/3 10:33*/
public interface ShopMapper extends BaseMapper<ShopEntity> {}

Service 接口

package com.chen.service;import com.baomidou.mybatisplus.extension.service.IService;
import com.chen.common.ResultBean;
import com.chen.dto.ShopDTO;
import com.chen.entity.ShopEntity;/*** @author whc* @date 2022/9/3 10:35*/
public interface ShopService extends IService<ShopEntity> {ResultBean<ShopDTO> queryById(Long id);
}

ServiceImpl 实现层

package com.chen.service.impl;import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.chen.common.ResultBean;
import com.chen.dto.ShopDTO;
import com.chen.entity.ShopEntity;
import com.chen.mapper.ShopMapper;
import com.chen.service.ShopService;
import com.chen.utils.RedisConstants;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;/*** @author whc* @date 2022/9/3 10:36*/
@Slf4j
@Service
public class ShopServiceImpl extends ServiceImpl<ShopMapper, ShopEntity> implements ShopService{@Autowiredprivate StringRedisTemplate stringRedisTemplate;@Overridepublic ResultBean<ShopDTO> queryById(Long id) {try {// 拼接 redis keyString key = RedisConstants.CACHE_SHOP_KEY + id;//从redis中获取是否已存在,若存在,则直接返回String json = stringRedisTemplate.opsForValue().get(key);//判断如果存在,就返回if (StrUtil.isNotBlank(json)) {ShopDTO shopDTO = JSONUtil.toBean(json, ShopDTO.class);return ResultBean.create(0, "success", shopDTO);}//从数据库查询数据 getById(id) 是 MyBatis-Plus 提供的查询方法,直接调用即可完成查询ShopEntity shopEntity = getById(id);//转换对象ShopDTO shopDTO = BeanUtil.toBean(shopEntity, ShopDTO.class);//将数据存入redisstringRedisTemplate.opsForValue().set(key, JSONUtil.toJsonStr(shopDTO));return ResultBean.create(0, "success", shopDTO);} catch (Exception e) {log.error("获取商品详情失败! e ==> {}", e);return ResultBean.create(-1, "获取商品详情失败! e ==> {}" + e);}}}

Controller层

package com.chen.controller;import com.chen.common.ResultBean;
import com.chen.dto.ShopDTO;
import com.chen.service.ShopService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;/*** @author whc* @date 2022/9/3 11:06*/
@RestController
@CrossOrigin
@RequestMapping("/shop")
public class ShopController {@Autowiredprivate ShopService shopService;@GetMapping("/{id}")public ResultBean<ShopDTO> queryShopById(@PathVariable("id") Long id) {return shopService.queryById(id);}
}

工具类

package com.chen.utils;/*** redis key 常量* @author whc* @date 2022/9/3 13:40*/
public class RedisConstants {public static final String CACHE_SHOP_KEY = "cache:shop:";public static final Long CACHE_SHOP_TTL = 30L;
}

✅测试接口

这里我使用了Redis可视化工具,RESP,地址:https://resp.app/zh/

打开后可以直接连接你的redis数据库,可视化展示

利用 ApiFox测试接口,可参考 【云原生】前后端分离项目下 如何优雅的联调程序?

第一次调用耗时 1.61s ,是因为我们第一次redis中无数据,走了查询数据库的操作,然后存入redis,总耗时1.61s

第二次调用

第二次调用直接走的缓存,可见效率提升了很多!

三、采用 微服务 Spring Boot 注解开启缓存

开启注解启动缓存

Spring 默认支持缓存,但版本必须在3.1以上,在启动类加入 @EnableCaching 开启即可

package com.chen;import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;/*** @author whc* @date 2022/9/3 10:27*/
//开启缓存支持
@EnableCaching
@MapperScan("com.chen.mapper")
@SpringBootApplication
public class MainApplication {public static void main(String[] args) {SpringApplication.run(MainApplication.class, args);}
}

✂️@CacheEnable 注解详解

@CacheEnable: 缓存存在,则使用缓存;不存在,则执行方法,并将结果塞入缓存

ShopServiceImpl 实现类

 @Cacheable(cacheNames = "shop", key = "#root.methodName")public ShopDTO queryById(Long id) {try {String key = RedisConstants.CACHE_SHOP_KEY + id;String json = stringRedisTemplate.opsForValue().get(key);if (StrUtil.isNotBlank(json)) {ShopDTO shopDTO = JSONUtil.toBean(json, ShopDTO.class);return shopDTO;}ShopEntity shopEntity = getById(id);//转换对象ShopDTO shopDTO = BeanUtil.toBean(shopEntity, ShopDTO.class);stringRedisTemplate.opsForValue().set(key, JSONUtil.toJsonStr(shopDTO), RedisConstants.CACHE_SHOP_TTL, TimeUnit.MINUTES);return shopDTO;} catch (Exception e) {log.error("获取商品详情失败! e ==> {}", e);return null;}}

➿调用接口测试

第一次调用,耗时很长

再次调用,走缓存

查看Redis可视化key

大小 1.11k 字节

再看json存入

大小 653 字节

综上考虑,出于内存的原因,我们选择使用json存入redis,更省内存!

⛵小结

以上就是【Bug 终结者】对 猿创征文 微服务 Spring Boot 整合Redis 实战开发解决高并发数据缓存 的简单介绍,缓存是我们比较常用的技术,在解决一些高并发场景下,我们巧妙的使用缓存可以极大的减轻服务器的压力,从而提高系统的高可用性,Redis基于内存并且是单线程的,所以说非常的快Redis缓存数据库很重要!

如果这篇【文章】有帮助到你,希望可以给【Bug 终结者】点个赞

猿创征文 | 微服务 Spring Boot 整合Redis 实战开发解决高并发数据缓存相关推荐

  1. 微服务Spring Boot 整合 Redis 实现 好友关注

    文章目录 ⛅引言 一.Redis 实现好友关注 -- 关注与取消关注 二.Redis 实现好友关注 -- 共同关注功能 ⛵小结 ⛅引言 本博文参考 黑马 程序员B站 Redis课程系列 在点评项目中, ...

  2. Spring boot - 整合 Redis缓存(上)

    一.配置Pom文件 在使用spring boot 2.0整合redis时遇到了好多问题,网上很多例子都是1.x版本的.故2.0没有折腾好所以将2.0降到了1.5.降级后由于thymeleaf版本也会从 ...

  3. Spring Boot基础学习笔记08:Spring Boot整合Redis

    文章目录 零.学习目标 1.熟悉Redis相关概念 2.掌握使用Spring Boot整合Redis 一.Redis概述 1.Redis简介 2.Redis优点 (1)存取速度快 (2)数据类型丰富 ...

  4. 十一、Spring Boot整合Redis(一)

    Spring Boot整合Redis    1. SpringBoot+单例Redis 1)引入依赖 <dependency>     <groupId>org.springf ...

  5. Spring boot整合Redis(入门教程)

    目录 源码分析 jedis VS lettuce 整合测试 导入依赖 配置连接 测试 存入字符串 存入对象 五大数据类型操作 自定义RedisConfig 存入对象 Redis工具类(常用API) 以 ...

  6. 大聪明教你学Java | Spring Boot 整合 Redis 实现访问量统计

    前言 之前开发系统的时候客户提到了一个需求:需要统计某些页面的访问量,记得当时还纠结了一阵子,不知道怎么去实现这个功能,后来还是在大佬的带领下借助 Redis 实现了这个功能.今天又回想起了这件事,正 ...

  7. Spring Boot 整合Redis 包含Java操作Redis哨兵 作者:哇塞大嘴好帥(哇塞大嘴好帅)

    Spring Boot 整合Redis 包含Java操作Redis哨兵 作者:哇塞大嘴好帥(哇塞大嘴好帅) 1. 配置环境 在SpringBoot2.0版本以后,原来使用的jedis被替换成为了let ...

  8. Spring boot整合Redis实现发布订阅(超详细)

    Redis发布订阅 基础知识 相关命令 订阅者/等待接收消息 发布者/发送消息 订阅者/成功接收消息 常用命令汇总 原理 Spring boot整合redis 导入依赖 Redis配置 消息封装类(M ...

  9. [由零开始]Spring boot 整合redis集群

    Spring boot 整合redis集群 一.环境搭建 Redis集群环境搭建:https://blog.csdn.net/qq497811258/article/details/108124697 ...

最新文章

  1. redis的导入导出需要特别注意的地方
  2. 研究能力培养的阶梯: 盐趣一对一科研项目
  3. scrapy-splash抓取动态数据例子十三
  4. iOS开发之APP内部切换语言
  5. 渗透测试python编程之端口扫描
  6. python3.5和3.7可以共存吗_centos7下Python和python3共存
  7. python语言程序设计 梁勇_计算机二级教程 Python语言程序设计,第9章Python标准库概览...
  8. mysql 各种导入导出
  9. python学习笔记(对象)
  10. java datediff函数_JPA Criteria 中 DATEDIFF 函数的使用
  11. bitnami下mysql配置-包含phpMyAdmin配置
  12. NIS服务的基本配置----视频下载
  13. 市场上最受欢迎的十大服装进销存软件
  14. 中科院信工所 考研面试经验贴
  15. 数据分析36计(27):分析师与用户研究员,玩转定量研究和定性研究,落地研究结论...
  16. 个人sublime定制
  17. 微调StyleGAN2模型
  18. 苹果开发者中心上传APP屏幕快照
  19. 内网工具 CS的基础使用
  20. wc 一个进程结果是2_用开放的wc创建一个Web组件

热门文章

  1. 企业云盘够快云库的「战斗与前行」
  2. c语言count函数的用法,java count函数用法
  3. matlab r2015b激活之后出错,ubuntu14.04下 安装matlabR2015b遇到的一些问题及其解决方法...
  4. K近邻算法的Python实现
  5. 【路径规划】基于模糊控制实现机器人路径规划matlab代码
  6. Centos7部署django项目
  7. 【JMeter】计数器的使用
  8. 09 线性回归及矩阵运算
  9. 力扣数组算法(c++)(代码随想录数组部分)
  10. 【Electron】vue+electron代码签名(mac篇)