使用Redis做缓存的小案例

        如果不了解Redis,可以查看本人博客:Redis入门

        Redis基于内存,因此查询速度快,常常可以用来作为缓存使用,缓存就是我们在内存中开辟一段区域来存储我们查询比较频繁的数据,这样,我们在下一次查询的时候,会直接去内存中查询,如果命中(查询到),就直接返回,否则就去数据库等在磁盘位置存储的数据进行查询,去磁盘硬盘等位置查询数据就比较慢了。因此,用好缓存对于我们的用户体验也是很重要的。

        本文基于springboot+mybatisplus+Redis进行实现。

        首先创建一个springboot项目:

        不勾选依赖:

        导入依赖:

        <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.5.2</version></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency>

        配置application.yaml

spring:redis:host: localhostport: 6379password: 123456datasource:type: com.zaxxer.hikari.HikariDataSourcedriver-class-name: com.mysql.cj.jdbc.Driverusername: rootpassword: rooturl: jdbc:mysql://localhost:3306/hongyan_sso?characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&allowMultiQueries=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=Asia/Shanghai&nullCatalogMeansCurrent=true&allowPublicKeyRetrieval=true

        编写实体类:

package com.qcby.springbootdata.pojo;import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;@TableName("t_user")
@Data
public class User {private Long id;private String userName;private String password;private String nickName;
}

        编写mapper:

package com.qcby.springbootdata.mapper;import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.qcby.springbootdata.pojo.User;
import org.apache.ibatis.annotations.Mapper;
import org.apache.tomcat.websocket.BackgroundProcess;@Mapper
public interface UserMapper extends BaseMapper<User> {
}

        编写controller:

package com.qcby.springbootdata.controller;import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.qcby.springbootdata.mapper.UserMapper;
import com.qcby.springbootdata.pojo.User;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.Arrays;
import java.util.List;@RestController
@Slf4j
public class UserController {@Resourceprivate UserMapper userMapper;@Resourceprivate RedisTemplate<String,String> redisTemplate;@GetMapping("/get-user-by-nick")public String getUserByNick(Long  id){String key = buildKey(String.valueOf(id));if(Boolean.TRUE.equals(redisTemplate.hasKey(key))){log.info("命中缓存,id:{}",id);return redisTemplate.boundValueOps(key).get();}User userPO = userMapper.selectById(id);if(userPO == null){redisTemplate.boundValueOps(key).set("暂无此人");return "暂无此人";}redisTemplate.boundValueOps(key).set(userPO.toString());return userPO.toString();}/*** 更新用户* 一般情况下,修改后删除就行了* 但是并发比较高,而且对数据比较敏感,比如说金钱,需要双删** @param userId   用户id* @param nickName 尼克名字* @return {@link String}* @throws InterruptedException 中断异常*/@GetMapping("/update-user-by-nick")public String updateUser(Long userId,String nickName) throws InterruptedException {User userPO = new User();userPO.setId(userId);userPO.setNickName(nickName);//这一步删除是为了保证,当sql指令发送给mysql以后,查询出来的值还是旧的redisTemplate.delete(buildKey(userId.toString()));userMapper.updateById(userPO);//这一步是为保证在sql指定发送给mysql的时候,来了查询,如果说这个时候的查寻还是修改之前的,导致缓存不更新redisTemplate.delete(buildKey(userId.toString()));return "22";}/*** 缓存预热*/@PostConstructpublic void initCache(){log.info("=========进行缓存预热=======================");List<Long> id  = Arrays.asList(101110L,101112L,101116L,101118L);List<User> userPOS = userMapper.selectList(new LambdaQueryWrapper<User>().in(User::getId, id));userPOS.stream().forEach(item->{redisTemplate.boundValueOps(buildKey(item.getId().toString())).set(item.toString());});}private String buildKey(String Id){return "user:Id_"+Id;}
}

        我们看一下controller中的思路:

        ①.@GetMapping("/get-user-by-nick")
            public String getUserByNick(Long  id)

        这个方法首先根据给出的查询参数构造Redis的key,我们查询Redis或者存Redis数据通常会构造一个key,按照这个key来存储值。

        首先从Redis数据库中查询,是否存在该查询结果的数据,如果存有,就直接拿取返回即可,否则走下一步。

        然后从数据库中查询需要的数据,首先判断这个数据是否存在,如果存在就存入Redis该数据值,否则说明不存在,直接存储“无此数据”即可。

        这个函数的大体思路就是,有数据就拿,没数据就存一个下次方便拿。

        ②.@GetMapping("/update-user-by-nick")
            public String updateUser(Long userId,String nickName)

        这个函数就是用来更新数据库数据,并且做到数据库与缓存之间保持同步。主要是考虑并发情况下,保证缓存数据和数据库数据的最终一致性。更新前删除缓存中的数据,保证尽可能的让其他进程或线程感知到数据库变化,进而在缓存中没有命中,进数据库中查询数据,此时,数据可能已经被更新了,或者还没有更新。

        第二次删除就是为了保证数据更新以后,删除缓存中数据,让其他进程或线程在缓存中无命中,进而进入数据库读取最新的数据,保证了最终一致性。

        ③.@PostConstruct
            public void initCache()

        这个方法主要是做缓存预热,在查询数据之前,预先将访问频繁的数据存入缓存,进而提高缓存命中,提高查询效率。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/757596.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C#,图论与图算法,有向图(Directed Graph)的环(Cycle)的普通判断算法与源代码

1 检查该图是否包含循环 给定一个有向图,检查该图是否包含循环。如果给定的图形至少包含一个循环,则函数应返回true,否则返回false。 方法:深度优先遍历可用于检测图中的循环。连接图的DFS生成树。只有当图中存在后缘时,图中才存在循环。后边是从节点到自身(自循环)或…

[视觉基础知识]: img to bev # include bev seg

参考&#xff1a;https://towardsdatascience.com/monocular-birds-eye-view-semantic-segmentation-for-autonomous-driving-ee2f771afb59 有源传感器&#xff08;lidar or radar&#xff09;得到的数据&#xff0c;天然就是一种bev表示&#xff08;x-y平面&#xff09;&#…

想速成AD?凡亿教育正式上线《Altium Designer 24:150讲操作速成实战课程》

随着电子技术的不断发展,芯片生产工艺迭代更新,印制电路板(PCB)结构日益复杂,从最早的单片机到双面板,再到复杂的多层板结构,电路板上的布线密度越来越高。 同时,随着DSP、ARM、FPGA、DDR等高速逻辑元件的应用,PCB的信号完整性和抗干扰性能显得尤为重要,光靠EDA软件的自动布线…

LeetCode每日一题 翻转二叉树(二叉树)

题目描述 给你一棵二叉树的根节点 root &#xff0c;翻转这棵二叉树&#xff0c;并返回其根节点。 示例 1&#xff1a; 输入&#xff1a;root [4,2,7,1,3,6,9] 输出&#xff1a;[4,7,2,9,6,3,1] 示例 2&#xff1a; 输入&#xff1a;root [2,1,3] 输出&#xff1a;[2,3,1]示…

Mistral AI vs. Meta:两大 Top 开源模型的对比

编者按&#xff1a; 随着大模型的不断升级和参数量的持续扩大&#xff0c;越来越多人开始重视大模型存在的硬件资源要求高、碳排放量较大等问题。如何在保持模型性能的同时&#xff0c;降低计算成本和资源消耗&#xff0c;成为了业界一个迫切需要解决的问题。 我们今天为大家带…

Servlet使用

文章目录 简介一、快速入门二、Servlet 执行流程三、Servlet 生命周期四、Servlet 方法介绍五、Servlet 体系结构六、Servlet urlPattern配置七、XML 配置方式编写 Servlet 简介 一、快速入门 <dependencies><dependency><groupId>javax.servlet</groupId…

个人网站制作 Part 9 添加发布、管理博客功能 | Web开发项目

文章目录 &#x1f469;‍&#x1f4bb; 基础Web开发练手项目系列&#xff1a;个人网站制作&#x1f680; 添加博客功能&#x1f528;使用Express和MongoDB&#x1f527;步骤 1: 创建博客模型&#x1f527;步骤 2: 创建博客路由 &#x1f528;使用前端框架&#x1f527;步骤 3:…

外包干了28天,技术退步明显......

说一下自己的情况&#xff0c;本科生&#xff0c;19年通过校招进入深圳某软件公司&#xff0c;干了接近4年的功能测试&#xff0c;今年年初&#xff0c;感觉自己不能够在这样下去了&#xff0c;长时间呆在一个舒适的环境会让一个人堕落!而我已经在一个企业干了四年的功能测试&a…

Testng框架集成新业务

总体框架设计见我另一篇博客&#xff1a;httpclienttestng接口自动化整体框架设计 <block&#xff1a;表示测试用例块> block后面是 测试用例的名称 ||接口名,该接口名在URL.txt里维护接口 ||get\post&#xff1a;表示请求的方法 get_1\2\3\4&#xff1a;代表加密 get: …

【保姆级教程】如何拥有GPT?(Proton邮箱版)

OnlyFans 订阅教程移步&#xff1a;【保姆级】2024年最新Onlyfans订阅教程 Midjourney 订阅教程移步&#xff1a; 【一看就会】五分钟完成MidJourney订阅 GPT-4.0 升级教程移步&#xff1a;五分钟开通GPT4.0 如果你需要使用Wildcard开通GPT4、Midjourney或是Onlyfans的话&am…

排序算法之选择排序介绍

目录 算法简介 算法描述 代码实现 算法简介 选择排序(Selection-sort)是一种简单直观的排序算法。它的工作原理&#xff1a;首先在未排序序列中找到最小&#xff08;大&#xff09;元素&#xff0c;存放到排序序列的起始位置&#xff0c;然后&#xff0c;再从剩余未排序元素…

Altair HyperStudy 多学科设计研究软件,帮助设计师探索和优化产品的性能和鲁棒性

HyperStudy 是一款多学科设计研究软件&#xff0c;可帮助设计师探索和优化产品的性能和鲁棒性。 HyperStudy 通过结合新型数学方法、预测性建模和数据挖掘功能的自动化流程&#xff0c;可智能、高效地探索任何系统模型的设计空间。在考虑多物理场约束的同时&#xff0c;引导用…

业务服务:redisson

文章目录 前言一、配置1. 添加依赖2. 配置文件/类3. 注入redission3. 封装工具类 二、应用1. RedisUtils工具类的基本使用 三、队列1. 工具类2. 普通队列3. 有界队列&#xff08;限制数据量&#xff09;4. 延迟队列&#xff08;延迟获取数据&#xff09;5. 优先队列&#xff08…

使用分治法解决矩阵乘法的Strassen算法及C代码示例

使用分治法解决矩阵乘法的Strassen算法及C代码示例 一、背景与意义二、分治法与矩阵乘法二、Strassen算法的基本思想三、Strassen算法的具体步骤四、Strassen算法的C代码实现五、Strassen算法的时间复杂度分析六、Strassen算法的优缺点及改进七、结论 一、背景与意义 在计算机…

LoRa模块在紧急救援与灾害管理中的作用:连接生命线

在灾害发生时&#xff0c;迅速、精准的信息传递和协调是救援工作中至关重要的一环。LoRa&#xff08;低功耗广域网&#xff09;模块以其长距离通信、低功耗和强大的穿透能力&#xff0c;为紧急救援与灾害管理提供了一种卓越的解决方案&#xff0c;成为连接生命线的关键技术。 1…

多个线程交替打印ABC

多个线程交替打印ABC package 多个线程交替打印ABC;import java.util.concurrent.BrokenBarrierException; import java.util.concurrent.CyclicBarrier;/*** Created with IntelliJ IDEA.** Author: AlenXu* Date: 2024/03/20/10:10* Description:*/ public class ThreadLoopP…

FPGA学习_Xilinx7系列FPGA基本结构

文章目录 前言一、7系列FPGA介绍1.1、芯片编号 二、基本组成单元2.1、可编程逻辑块CLB&#xff08;Configable Logic Block&#xff09;2.2、可编程输入输出单元&#xff08;IOB&#xff09;2.3、嵌入式块RAM&#xff08;Block RAM&#xff09;2.4、底层内嵌功能单元2.5、内嵌专…

罐头鱼AI视频混剪系统|视频矩阵运营获客

罐头鱼AI视频混剪系统 在当今数字化时代&#xff0c;视频内容已经成为吸引观众注意力的重要媒介之一。为了帮助用户更轻松地创建、编辑和发布视频内容&#xff0c;q1977470120罐头鱼AI推出了全新的视频混剪系统&#xff0c;让您的视频制作过程更加智能高效。让我们一起来看看罐…

网络工程师之路由交换技术篇

网络工程师之路由交换技术篇 路由交换之技术篇ARPICMPBPDUIPv6IP编址MAC其他技术点参考 以下均为个人笔记&#xff0c;摘录到csdn做备份 路由交换之技术篇 ARP Operation Code指定了ARP报文的类型&#xff0c; 包括ARP request 和ARP reply&#xff1b;取值为1或者2 &#x…

linux系统------------Mysql数据库

目录 一、数据库基本概念 1.1数据(Data) 1.2表 1.3数据库 1.4数据库管理系统(DBMS) 数据库管理系统DBMS原理 1.5数据库系统&#xff08;DBS) 二、数据库发展史 1、第一代数据库 2、第二代数据库 3、第三代数据库 三、关系型数据库 3.1关系型数据库应用 3.2主流的…