Springboot实战——黑马点评之缓存

news/2024/11/17 19:55:42/文章来源:https://www.cnblogs.com/Wyuf1314/p/18363417

Springboot黑马点评——缓存

1 缓存初识与简单实现

1.1 根据商铺id的缓存查询

基础缓存实现:

考虑到有数据会同时存在于数据库和缓存中,所以:
Q:数据库和缓存的数据一致性问题?
A:三种缓存更新策略用来解决一致性问题

1.2 缓存更新策略的选择

  • 第一种:内存淘汰
  • 第二种:超时剔除
  • 第三种:主动更新(自行编码)

1.2.1 主动更新策略:三种写缓存

一般主动更新策略最通用,主动更新策略又有三种写缓存的方式:

一般使用第一种主动更新策略
即 调用者对缓存和数据库的一致性的操作编码 两者同时操作
同时我们需要考虑以下三点问题

选择更新数据库删除缓存 避免更多的无效写操作
选择先操作数据库再删除缓存

  • 不同场景对于缓存更新策略的选择

2 缓存穿透与缓存击穿问题的解决方案

2.1 缓存穿透

常见的解决方法有两种:

  • 缓存空对象

  • 布隆过滤

2.1.1 缓存穿透解决方案

1.1那样读取数据:
先查Redis->Redis命中则转换存储格式返回
->Redis未命中则到数据库中查找
->数据库未命中则返回404数据不存在
->数据库命中则将数据转换存储格式写入Redis
(即下图的流程图)

存在缓存穿透的风险:若有恶意查询不存在数据的请求频繁插入,将会给数据库查询带来很大压力

解决缓存穿透的方法:

  • 若从数据库查询为空,则将该空值存入Redis中
    (设置有效时间为2分钟,以防止内存大量置空消耗)
  • 在Redis中置空的店铺在下一次用户查找时,非正常返回不存在错误信息而不是用户实体

2.2 缓存雪崩

2.3 缓存击穿

满足两个条件:高并发访问的热点数据/缓存重建业务很复杂
多个线程同时访问,而此时该业务的缓存数据已失效
则对数据库的持续查询造成很大负担且需要轮询等待


解决缓存击穿的两种方法:

  • 互斥锁
  • 逻辑过期


2.4 实现缓存击穿解决思路

2.4.1 使用简易互斥锁(redis中的SETNX方法)



2.4.2 使用逻辑过期时间

逻辑锁:
前提条件:当前查询的对象属于热点key,例如属于当前活动或折扣商品,所以后台会在初始阶段将该热点数据存入Redis中(封装+逻辑过期时间),请求大概率会直接命中
简单来说就是 将过期时间封装在键值中作为该对象的逻辑过期时间(logic expiretime) 而存入Redis时不给该键值设置expiretime 对外显示为永久生效的键值
在命中该键值时->无论过期时间是否到期->统一将当前(旧)数据返回给前端->
->如果过期时间已到期->开启独立线程 重新从数据库中载入
->尝试获取互斥锁(和互斥锁逻辑相同)



【知识点】:
开启独立线程 借助 java的线程池来实现:
线程池是一种常用的并发编程工具,它允许我们有效地管理和控制并发任务的执行。newFixedThreadPool方法接受一个整数参数,表示线程池中的线程数量。一旦线程池创建完成,我们就可以使用ExecutorService接口的方法来提交任务到线程池中执行。

ExecutorService executorService = Executors.newFixedThreadPool(5);
executorService.submit(() -> {...提交至线程池中执行的内容})

newFixedThreadPool默认使用无界队列(LinkedBlockingQueue)来保存等待执行的任务。这意味着如果线程池中的线程都在忙碌状态,新提交的任务将一直排队等待,而不会立即被拒绝。然而,这也可能导致队列中的任务数量无限制增长,从而消耗过多的内存资源。因此,在实际应用中,我们可以考虑使用有界队列来限制队列的最大容量,当队列满时,新提交的任务将被拒绝执行。
在应用程序结束时,我们需要确保正确地关闭线程池,以释放系统资源。ExecutorService接口提供了shutdown和shutdownNow两个方法来关闭线程池。
1)shutdown方法用于启动线程池的关闭序列。已经提交的任务将继续执行,但新的任务将不再接受。当所有任务都执行完毕后,线程池中的线程将自动终止。
2)shutdownNow方法尝试停止所有正在执行的任务,并返回等待执行的任务列表。与shutdown方法不同,shutdownNow方法并不保证能够停止所有正在执行的任务,但它会尝试中断正在执行的任务。

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

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

相关文章

SQLite 和 DB Browser SQLite介绍安装

SQLite介绍SQLite是轻量级的嵌入式数据库,‌无需独立服务器进程(不用独占服务器的资源),‌适合单用户或低并发场景;‌SQLite功能相对简单,‌不支持存储过程、‌触发器等高级特性,‌数据安全性较低;‌SQLite适用于嵌入式设备、‌移动应用和轻量级桌面应用DB Browser SQLit…

Linear Algebra

线性代数有两大主线第一条主线,是以行列式、矩阵、向量组为工具,研究线性方程组的解法以及解的结构; 第二条主线,是以特征值、特征向量、相似理论为依据,研究二次型的标准化.线性方程组 核心问题:线性方程组是否一定有解?有解时,有多少个解? 如何求出线性方程组的解?…

使用pkg将node项目打包成exe

1、node版本(我用的这两个版本都没问题):node:v14.18.1、v14.18.22、安装pkg(推荐使用v5.7.0):npm install -g pkg@5.7.03、创建pkg_test文件夹,并初始化一个node项目:mkdir pkg_testcd pkg_test npm init -y4、创建一个index.js,并写入部分代码如图 5、完成上面的步骤后…

第四章 Python操作redis(操作案例)

一、python对redis基本操作 (1)连接redis # 方式1 import redisr = redis.Redis(host=127.0.0.1, port=6379) r.set(foo, Bar) print(r.get(foo))# 方式2 import redispool = redis.ConnectionPool(host=127.0.0.1, port=6379) r = redis.Redis(connection_pool=pool) r.set(…

[Java手撕]线程安全的转账

首先来看线程不安全的转账 public class Bank {private int[] accounts;public Bank() {this.accounts = new int[10];for (int i = 0; i < 10; i++) {accounts[i] = 1000;}}public void transfer(int from, int to, int amount) {if (accounts[from] >= amount) {accoun…

深入解析财务报表:如何抓住关键指标作出明智决策

一、概述 财务报表中包含了丰富的信息,但如果在分析时缺乏明确的思路或忽略重点,很容易被复杂的数据搞得无所适从。本文将介绍财务报表中的关键指标,包括资产负债率的分析、净资产收益率的解读,以及销售复合增长率的计算,帮助大家有针对性地理解和学习这些内容。二、关键指…

第三章 redis数据类型

redis数据类型redis可以理解成一个全局的大字典,key就是数据的唯一标识符。根据key对应的值不同,可以划分成5个基本数据类型。redis = {"name":"yuan","scors":["100","89","78"],"info":{"name…

5. 概述(General description)

5. 概述(General description) 5.1. Introduction 5.1. A low-rate wireless personal area network (LR-WPAN) is a simple, low-cost communication network that allows wireless connectivity in applications with limited power and relaxed throughput requirements. …

jmeter中提取token值(正则表达式,)

jmeter中提取token值(正则表达式) 一、接口前准备 案例链接:http://shop.duoceshi.com/ uiid接口: http://manage.duoceshi.com/auth/code get请求 登录接口: http://manage.duoceshi.com/auth/login POST请求 请求参数: {"username":"admin","…

操作系统-线程

一、线程介绍线程是操作系统能内够进行运算、执行的最小单位,它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。​ 总结:线程是进程的一部分,是进程内负责执行的单位,进程…

[学习笔记]在不同项目中切换Node.js版本

@目录使用 Node Version Manager (NVM)安装 NVM使用 NVM 安装和切换 Node.js 版本为项目指定 Node.js 版本使用环境变量指定 Node.js安装多个版本的 Node.js设置环境变量验证配置使用 npm 脚本切换 在开发中,可能会遇到不同的Vue项目需要不同的Node.js,在开发机上如何快速切换…