缓存与分布式锁

一、缓存

1、缓存使用

        为了系统性能的提升,我们一般都会将部分数据放入缓存中,加速访问。

        适合放入缓存的数据有:

                即时性、数据一致性要求不高的;访问量大且更新频率不高的数据。

        在开发中,凡是放入缓存中的数据我们都应该指定过期时间,使其可以在系统即使没有主动更新数据也能自动触发数据加载进缓存的流程。避免业务崩溃导致的数据永久不一致问题。

2、使用redis作为缓存

 引入依赖

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

配置文件

spring:
    redis:
        host: 192.168.56.10
        port: 6379

使用RedisTemplate操作redis 

@Autowired
StringRedisTemplate stringRedisTemplate;

@Test
public void testStringRedisTemplate(){
    ValueOperations<String, String> ops = stringRedisTemplate.opsForValue();
    ops.set("hello","world_"+ UUID.randomUUID().toString());
    String hello = ops.get("hello");
    System.out.println(hello);
}

二、缓存失效问题

1、缓存穿透

        缓存穿透是指查询一个一定不存在的数据,由于缓存是不命中,将去查询数据库,但是数 据库也无此记录,我们没有将这次查询的 null 写入缓存,这将导致这个不存在的数据每次 请求都要到存储层去查询,失去了缓存的意义。

        在流量大时,可能 DB 就挂掉了,要是有人利用不存在的 key 频繁攻击我们的应用,这就是 漏洞。

        解决: 缓存空结果、并且设置短的过期时间。

2、缓存雪崩

        缓存雪崩是指在我们设置缓存时采用了相同的过期时间,导致缓存在某一时刻同时失效,请求全部转发到 DB,DB 瞬时压力过重雪崩。

        解决: 原有的失效时间基础上增加一个随机值,比如 1-5 分钟随机,这样每一个缓存的过期时间的 重复率就会降低,就很难引发集体失效的事件。

3、缓存击穿

        对于一些设置了过期时间的 key,如果这些 key 可能会在某些时间点被超高并发地访问, 是一种非常“热点”的数据。 这个时候,需要考虑一个问题:如果这个 key 在大量请求同时进来前正好失效,那么所 有对这个 key 的数据查询都落到 db,我们称为缓存击穿。

        解决: 加锁。缓存不存在时。在查询数据库前先获取锁,在得到锁后,再次确认缓存是否存在,不存在则查询数据库并更新缓存。

三、缓存数据的一致性

1、保证一致性

双写模式

失效模式

读写锁

读数据等待写数据整个操作完成。

四、分布式锁

1、分布式锁与本地锁

本地锁只能锁住当前进程,在分布式情况下,有多少个服务就会产生几把锁。

2、分布式锁实现

public Map<String, List<Catelog2Vo>> getCatalogJsonFromDBWithRedisLock() {

        //1、占用分布式锁 锁和过期时间一起设置  原子性操作
        String uuid = UUID.randomUUID().toString();
        Boolean lock = redisTemplate.opsForValue().setIfAbsent("lock", uuid, 300, TimeUnit.SECONDS); //锁设置的时间很长,防止业务执行期间锁过期  todo 自动续锁
        if (lock) { //加锁成功
            System.out.println("获取分布式锁成功");
            //设置过期时间, 必须和加锁是原子性操作
            //redisTemplate.expire("lock", 30, TimeUnit.SECONDS);
            Map<String, List<Catelog2Vo>> lockThenDo = null;
            try {
                lockThenDo = getLockThenDo();
            } finally {
                //lua 脚本解锁
                String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
                redisTemplate.execute(new DefaultRedisScript<Long>(script, Long.class), Collections.singletonList("lock"), uuid);
            }

            //解锁,不能随便删除别人的锁
            //两步:获取值对比, 对比成功删除    一定要是原子性
//            redisTemplate.delete("lock");
//            String uuidString = redisTemplate.opsForValue().get("lock");
//            if (uuid.equalsIgnoreCase(uuidString)) {
//                //删除自己的锁
//                redisTemplate.delete("lock");
//            }

            return lockThenDo;
        } else {
            //加锁失败重试  自旋的方式
            //可以设置休眠 后重试
            System.out.println("获取分布式锁不成功,等待重试。。。。");
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return getCatalogJsonFromDBWithRedisLock();
        }
    }

3、Redisson完成分布式锁

1、简介

        Redisson 是架设在 Redis 基础上的一个 Java 驻内存数据网格(In-Memory Data Grid)。充分的利用了 Redis 键值数据库提供的一系列优势,基于 Java 实用工具包中常用接口,为使用者提供了一系列具有分布式特性的常用工具类。

RLock lock = redisson.getLock("anyLock");// 最常见的使用方法
lock.lock();
// 加锁以后 10 秒钟自动解锁// 无需调用 unlock 方法手动解锁
lock.lock(10, TimeUnit.SECONDS);
// 尝试加锁,最多等待 100 秒,上锁以后 10 秒自动解锁 
Boolean res = lock.tryLock(100,10, TimeUnit.SECONDS);
if (res) {
    try {
        ...
    } finally {
        lock.unlock();
    }
}

五、springCache

1、简介

        Spring Cache利用了AOP,实现了基于注解的缓存功能,并且进行了合理的抽象,业务代码只需要简单地加一个注解,就能实现缓存功能了。

2、使用

启用缓存

//只需要在配置类中添加 @EnableCaching
@Configuration
@EnableCaching
public class CachingConfig {

    @Bean
    public CacheManager cacheManager() {
        return new ConcurrentMapCacheManager("addresses");
    }
}

 在需要缓存的数据方法加上注解

//    @CacheEvict(value = "catagory", allEntries = true)   第二种方法  批量删除某个分区下的所有数据
//    @Caching(evict = {
//            @CacheEvict(value = "catagory", key = "'getLevel1Cate'"),   //同时进行多种缓存操作  第一种方法 todo
//            @CacheEvict(value = "catagory", key = "'getCatelogJson'")
//    })
//    @CachePut //双写模式

    @CacheEvict(value = "catagory", key = "'getLevel1Cate'") //修改后自动删除缓存
    @Transactional
    @Override
    public List<CategoryEntity> updateCascade(CategoryEntity category) {}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Git 命令行快速入门

前言 &#xff08;1&#xff09;新手个人建议使用TortoiseGit这类图形化界面来上手学习。 &#xff08;2&#xff09;如果一定需要用命令行进行操作&#xff0c;可以按照B站&#xff1a;程式与网页开发者必备技能&#xff01;Git 和 GitHub 零基础快速上手&#xff0c;轻松掌握…

构造与操作链栈

归纳编程学习的感悟, 记录奋斗路上的点滴, 希望能帮到一样刻苦的你! 如有不足欢迎指正! 共同学习交流! 🌎欢迎各位→点赞 👍+ 收藏⭐ + 留言​📝心态决定高度,细节决定成败! 链栈是数据结构中栈的一种实现方式,它利用链表(通常是单链表)来存储栈中的元…

【触摸屏】【红十字会学习系统】功能模块:视频 + AI拍照合成

项目背景 提升公众急救能力&#xff1a;确保每个人都能在紧急情况下采取正确的急救措施&#xff0c;减少伤害&#xff0c;挽救生命。培养人道主义价值观&#xff1a;通过教育和培训&#xff0c;传播红十字精神&#xff0c;促进社会对弱势群体的关注与支持。建立社区响应网络&a…

1. InternLM - 入门岛

第1关 Linux 基础知识 1. 完成SSH连接与端口映射并运行hello_world.py SSH连接配置 # wsl2中生成密钥对&#xff08;~/.ssh/id_rsa, ~/.ssh/id_rsa.pub&#xff09; ssh-keygen -t rsa# 将id_rsa.pub在internStudio作为公钥导入SSH登录 $ ssh -p 38871 rootssh.intern-ai.o…

5.SpringBoot核心源码-启动类源码分析

目录 概述技巧spring boot 如何启动应用程序run方法里面核心逻辑 SpringApplicaiton.run(xxx.class,args)结束 概述 SpringBoot核心源码-启动类源码分析 技巧 如何给外部源码加注释&#xff0c;想要在源码中添加自己的注释&#xff0c;会弹出 file is read only&#xff0c;代…

Java核心技术【二十二】Java的I/O流处理:深入文件读写操作、缓冲流、序列化与NIO

Java的I/O流处理&#xff1a;深入文件读写操作、缓冲流、序列化 在Java编程中&#xff0c;I/O流是处理输入输出操作的基础&#xff0c;特别是在文件读写、网络通信等领域。本文将在前文的基础上&#xff0c;进一步探讨缓冲流、序列化以及NIO&#xff08;New I/O&#xff09;在…

从0开始的STM32HAL库学习2

外部中断(HAL库GPIO讲解) 今天我们会详细地学习STM32CubeMX配置外部中断&#xff0c;并且讲解HAL库的GPIO的各种函数。 准备工作&#xff1a; 1、STM32开发板&#xff08;我的是STM32F103C8T6&#xff09; 2、STM32CubeMx软件、 IDE&#xff1a; Keil软件 3、STM32F1xx/ST…

01- 收入数据集【Pytorch入门实战】

目录 一、机器学习基础 二、实战例子 1.数据集分析 2.实战训练 3.总结 三、参考资料 一、机器学习基础 为了解决这个问题&#xff0c;人们想到数据驱动方法&#xff0c;也就是让计算机从现有的大量的带标签图片电学习规律&#xff0c;一旦计算机学习到了其中的规律&…

sip协议栈简介

SIP协议栈简介 SIP协议栈流程 数据链路层&#xff1a;当SIP消息从网络中传输到达TCP/IP协议栈时&#xff0c;首先被接收到的是数据链路层的数据帧。数据链路层会对数据帧进行解封装&#xff0c;得到网络层的IP数据报。 网络层&#xff1a;网络层会对IP数据报进行解析&#xf…

1.27、基于径向基神经网络的曲线拟合(matlab)

1、基于径向基神经网络的曲线拟合简介及原理 1)原理简介 基于径向基神经网络(Radial Basis Function Neural Network, RBFNN)的曲线拟合是一种常用的非线性拟合方法,通过在输入空间中使用径向基函数对数据进行处理,实现对非线性关系的拟合。 RBFNN的基本原理是将输入空…

Java基础(十九):集合框架

目录 一、Java集合框架体系二、Collection接口及方法1、添加2、判断3、删除4、其它 三、Iterator(迭代器)接口1、Iterator接口2、迭代器的执行原理3、foreach循环 四、Collection子接口1&#xff1a;List1、List接口特点2、List接口方法3、List接口主要实现类&#xff1a;Array…

【Hive SQL 每日一题】在线峰值人数计算

文章目录 测试数据需求说明需求实现 测试数据 -- 创建 user_activity 表 DROP TABLE IF EXISTS user_activity ; CREATE TABLE user_activity (user_id STRING,activity_start TIMESTAMP,activity_end TIMESTAMP );-- 插入数据 INSERT INTO user_activity VALUES (user1, 2024…

算效最高的智算中心上线,天府智算为AI产业带来哪些启示?

四川简阳&#xff0c;地处川中、控扼巴峡&#xff0c;自古乃成渝、川鄂之间的交通重镇&#xff0c;素有“天府雄州”之美誉。 步入数字经济时代&#xff0c;“天府雄州”得天独厚的地理位置再次彰显出巨大的战略价值。简阳市成为成渝算力枢纽的天府数据中心集群关键布局点&…

element ui ts table重置排序

#日常# 今天带的实习生&#xff0c;在遇到开发过程中&#xff0c;遇到了element ui table 每次查询的时候都需要重置排序方式&#xff0c;而且多个排序是由前端排序。 <el-table :data"tableData" ref"restTable"> </<el-table> <script…

bi项目笔记

1.bi是什么 bi项目就是商业智能系统&#xff0c;也就是数据可视画、报表可视化系统&#xff0c;如下图的就是bi项目了 2.技术栈

深入了解 MySQL 的 EXPLAIN 命令

一、什么是 EXPLAIN 命令&#xff1f; EXPLAIN 命令用于显示 MySQL 如何执行某个 SQL 语句&#xff0c;尤其是 SELECT 语句。通过 EXPLAIN 命令&#xff0c;可以看到查询在实际执行前的执行计划&#xff0c;这对于优化查询性能至关重要。 二、EXPLAIN 的基本用法 要使用 EXP…

什么时候要用弗洛伊德算法

分析一下题目&#xff0c;我们看到数据量只有一百&#xff0c;这个时候我们就要注意是否是要用弗洛伊德算法&#xff0c;然后接着我们还需要枚举每一种情况&#xff0c;我们可以用到next_permutation这个方法 #include<bits/stdc.h> using namespace std;const int N 10…

matlab R2016b安装cplex12.6,测试时cplex出现出现内部错误的解决方法

问题场景 网上搜索matlabyalmipcplex的安装教程&#xff0c;跟着步骤操作即可&#xff0c;假如都安装好了&#xff0c;在matlab中测试安装是否成功&#xff0c;出现以下问题&#xff1a; 1、matlab中设置路径中添加了yalmip和cplex路径&#xff0c;在命令窗口中输入yalmiptest…

实现将Nginx的每个网站配置单独的nginx配置文件——每个网站单独管理

一、问题描述 Nginx默认地配置文件【nginx.conf】是包含了所有网站的配置内容,如果我们需要配置很多网站的话,就需要在默认的配置文件中给每个网站都添加一条server记录,这样下去nginx默认配置文件会变得很大,很难管理(比如有些网站不使用了,需要注销掉,也需要到该文件操…

openEuler 安装 podman 和 podman compose

在 openEuler 22.03 LTS SP4 中&#xff0c;你可以使用 dnf 包管理器来安装 Podman 和 Podman Compose。openEuler 默认使用 dnf 作为包管理器&#xff0c;所以这是安装软件的首选方式。 关于 openEuler 22.03 LTS SP4 下载地址&#xff1a; https://www.openeuler.org/zh/dow…