当前位置: 首页 > news >正文

缓存-分布式锁-原理和基本使用

分布式锁原理和使用

 

自旋 

 public Map<String, List<Catelog2Vo>> getCatalogJsonFromDBWithRedisLock() {Boolean b = redisTemplate.opsForValue().setIfAbsent(Lock, Lock, Duration.ofMinutes(1));if (!b) {int i = 10;while (i > 0) {Object result = redisTemplate.opsForValue().get(CATALOG_JSON);try {TimeUnit.MILLISECONDS.sleep(100);} catch (InterruptedException e) {throw new RuntimeException(e);}if (result != null) {System.out.println("命中缓存 db lock");return (Map<String, List<Catelog2Vo>>) result;}i--;}throw new RuntimeException("系统繁忙,请重新访问");}//1.查出所有1级分类List<CategoryEntity> selectList = baseMapper.selectList(null);/*** 将数据库的多次查询变成一次*/System.out.println("查询了数据库");//2. 封装数据List<CategoryEntity> level1Category = selectList.stream().filter(s -> s.getParentCid().equals(0L)).collect(Collectors.toList());Map<String, List<Catelog2Vo>> map = level1Category.stream().collect(Collectors.toMap(k -> k.getCatId().toString(), v -> {//1.每一个的一级分类,查到1级分类的所有二级分类List<CategoryEntity> categoryEntities = selectList.stream().filter(s -> s.getParentCid().equals(v.getCatId())).collect(Collectors.toList());List<Catelog2Vo> catelog2VoList = categoryEntities.stream().map(c -> {Catelog2Vo catelog2Vo = new Catelog2Vo();catelog2Vo.setId(c.getCatId().toString());catelog2Vo.setName(c.getName());catelog2Vo.setCatalog1Id(v.getCatId().toString());List<CategoryEntity> categoryEntities1 = selectList.stream().filter(s -> s.getParentCid().equals(c.getCatId())).collect(Collectors.toList());List<Catelog2Vo.Catelog3Vo> collect = categoryEntities1.stream().map(c3 -> {Catelog2Vo.Catelog3Vo catelog3Vo = new Catelog2Vo.Catelog3Vo();catelog3Vo.setId(c3.getCatId().toString());catelog3Vo.setName(c3.getName());catelog3Vo.setCatalog2Id(c.getCatId().toString());return catelog3Vo;}).collect(Collectors.toList());catelog2Vo.setCatalog3List(collect);return catelog2Vo;}).collect(Collectors.toList());return catelog2VoList;}));if (map == null) {/*** 解决缓存穿透*/map = new HashMap<>();}redisTemplate.opsForValue().set(CATALOG_JSON, map, Duration.ofDays(1));redisTemplate.delete(Lock);return map;}

 public Map<String, List<Catelog2Vo>> getCatalogJsonFromDBWithRedisLock() {String uuid = UUID.randomUUID().toString();Boolean b = redisTemplate.opsForValue().setIfAbsent(Lock, uuid, Duration.ofMinutes(1));if (!b) {int i = 10;while (i > 0) {Object result = redisTemplate.opsForValue().get(CATALOG_JSON);try {TimeUnit.MILLISECONDS.sleep(100);} catch (InterruptedException e) {throw new RuntimeException(e);}if (result != null) {System.out.println("命中缓存 db lock");return (Map<String, List<Catelog2Vo>>) result;}i--;}throw new RuntimeException("系统繁忙,请重新访问");}//1.查出所有1级分类List<CategoryEntity> selectList = baseMapper.selectList(null);/*** 将数据库的多次查询变成一次*/System.out.println("查询了数据库");//2. 封装数据List<CategoryEntity> level1Category = selectList.stream().filter(s -> s.getParentCid().equals(0L)).collect(Collectors.toList());Map<String, List<Catelog2Vo>> map = level1Category.stream().collect(Collectors.toMap(k -> k.getCatId().toString(), v -> {//1.每一个的一级分类,查到1级分类的所有二级分类List<CategoryEntity> categoryEntities = selectList.stream().filter(s -> s.getParentCid().equals(v.getCatId())).collect(Collectors.toList());List<Catelog2Vo> catelog2VoList = categoryEntities.stream().map(c -> {Catelog2Vo catelog2Vo = new Catelog2Vo();catelog2Vo.setId(c.getCatId().toString());catelog2Vo.setName(c.getName());catelog2Vo.setCatalog1Id(v.getCatId().toString());List<CategoryEntity> categoryEntities1 = selectList.stream().filter(s -> s.getParentCid().equals(c.getCatId())).collect(Collectors.toList());List<Catelog2Vo.Catelog3Vo> collect = categoryEntities1.stream().map(c3 -> {Catelog2Vo.Catelog3Vo catelog3Vo = new Catelog2Vo.Catelog3Vo();catelog3Vo.setId(c3.getCatId().toString());catelog3Vo.setName(c3.getName());catelog3Vo.setCatalog2Id(c.getCatId().toString());return catelog3Vo;}).collect(Collectors.toList());catelog2Vo.setCatalog3List(collect);return catelog2Vo;}).collect(Collectors.toList());return catelog2VoList;}));if (map == null) {/*** 解决缓存穿透*/map = new HashMap<>();}redisTemplate.opsForValue().set(CATALOG_JSON, map, Duration.ofDays(1));Object o = redisTemplate.opsForValue().get(Lock);if (o != null && o.equals(uuid)) {redisTemplate.delete(Lock);}return map;}

还是有问题

因为 在传输过程中需要耗时,这时候如果过期KEY,让其他线程进来创建KEY,然后数据返回到之前那个线程,删除KEY,又会把别人新加进来的key给删掉

获取值对比+对比成功删除=原子操作

 redis+lua脚本实现

 public static final String Lock = "Lock";
  public Map<String, List<Catelog2Vo>> getCatalogJsonFromDBWithRedisLock() {String uuid = UUID.randomUUID().toString();Boolean b = redisTemplate.opsForValue().setIfAbsent(Lock, uuid, Duration.ofMinutes(5));if (!b) {System.out.println("获取分布式锁失败,等待重试");int i = 10;while (i > 0) {Object result = redisTemplate.opsForValue().get(CATALOG_JSON);try {TimeUnit.MILLISECONDS.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}if (result != null) {System.out.println("命中缓存 db lock");return (Map<String, List<Catelog2Vo>>) result;}i--;}throw new RuntimeException("系统繁忙,请重新访问");}//1.查出所有1级分类/*** 将数据库的多次查询变成一次*/System.out.println("获取分布式锁成功");//2. 封装数据Map<String, List<Catelog2Vo>> map = null;try {System.out.println("查询了数据库");List<CategoryEntity> selectList = baseMapper.selectList(null);List<CategoryEntity> level1Category = selectList.stream().filter(s -> s.getParentCid().equals(0L)).collect(Collectors.toList());map = level1Category.stream().collect(Collectors.toMap(k -> k.getCatId().toString(), v -> {//1.每一个的一级分类,查到1级分类的所有二级分类List<CategoryEntity> categoryEntities = selectList.stream().filter(s -> s.getParentCid().equals(v.getCatId())).collect(Collectors.toList());List<Catelog2Vo> catelog2VoList = categoryEntities.stream().map(c -> {Catelog2Vo catelog2Vo = new Catelog2Vo();catelog2Vo.setId(c.getCatId().toString());catelog2Vo.setName(c.getName());catelog2Vo.setCatalog1Id(v.getCatId().toString());List<CategoryEntity> categoryEntities1 = selectList.stream().filter(s -> s.getParentCid().equals(c.getCatId())).collect(Collectors.toList());List<Catelog2Vo.Catelog3Vo> collect = categoryEntities1.stream().map(c3 -> {Catelog2Vo.Catelog3Vo catelog3Vo = new Catelog2Vo.Catelog3Vo();catelog3Vo.setId(c3.getCatId().toString());catelog3Vo.setName(c3.getName());catelog3Vo.setCatalog2Id(c.getCatId().toString());return catelog3Vo;}).collect(Collectors.toList());catelog2Vo.setCatalog3List(collect);return catelog2Vo;}).collect(Collectors.toList());return catelog2VoList;}));if (map == null) {/*** 解决缓存穿透*/map = new HashMap<>();}redisTemplate.opsForValue().set(CATALOG_JSON, map, Duration.ofDays(1));} catch (Exception e) {e.printStackTrace();} finally {//lua脚本解锁//如果获取key等于传过来的值,就执行删除操作,否则就不执行String script="if redis.call('get',KEYS[1])==ARGV[1] then return redis.call('del',KEYS[1]) else return 0 end";Long execute = redisTemplate.execute(new DefaultRedisScript<Long>(script, Long.class), Arrays.asList(Lock), uuid);if (execute==1){System.out.println("原子删锁成功");}else {System.out.println("原子删锁失败");}}return map;}

 只有一个查询了数据库

相关文章:

缓存-分布式锁-原理和基本使用

分布式锁原理和使用 自旋 public Map<String, List<Catelog2Vo>> getCatalogJsonFromDBWithRedisLock() {Boolean b redisTemplate.opsForValue().setIfAbsent(Lock, Lock, Duration.ofMinutes(1));if (!b) {int i 10;while (i > 0) {Object result redisTe…...

判断国内ip

php代码 //是否国内ip function isChinaIP($ip) {saveLog("---isChinaIP----------");$url "https://searchplugin.csdn.net/api/v1/ip/get?ip".$ip;// 发送HTTP请求$response file_get_contents($url);$utf8String mb_convert_encoding($response, &…...

linux修改内核实现禁止被ping(随手记)

概述 Linux默认允许被ping。其主要决定因素为&#xff1a; 内核参数防火墙&#xff08;iptables/firewall&#xff09; 以上的决定因素是与的关系&#xff0c;即需要均满足。 因此&#xff0c;修改linux禁被ping有以上两种方法可以实现。 修改内核文件使禁ping 1. 临时生…...

mac M1安装 VSCode

最近在学黑马程序员Java最新AI若依框架项目开发&#xff0c;里面前端用的是Visual Studio Code 所以我也就下载安装了一下&#xff0c;系统是M1芯片的&#xff0c;安装过程还是有点坑的写下来大家注意一下 1.在appstore中下载 2.在系统终端中输入 clang 显示如下图 那么在终端输…...

代码随想录算法训练营第二十七天 |56. 合并区间 738.单调递增的数字 968.监控二叉树 (可跳过)

56. 合并区间 以数组 intervals 表示若干个区间的集合&#xff0c;其中单个区间为 intervals[i] [starti, endi] 。请你合并所有重叠的区间&#xff0c;并返回 一个不重叠的区间数组&#xff0c;该数组需恰好覆盖输入中的所有区间 。 示例 1&#xff1a; 输入&#xff1a;in…...

网络基础:IS-IS协议

IS-IS&#xff08;Intermediate System to Intermediate System&#xff09;是一种链路状态路由协议&#xff0c;最初由 ISO&#xff08;International Organization for Standardization&#xff09;为 CLNS&#xff08;Connectionless Network Service&#xff09;网络设计。…...

Java面试八股之如何提高MySQL的insert性能

如何提高MySQL的insert性能 提高MySQL的INSERT性能可以通过多种策略实现&#xff0c;以下是一些常见的优化技巧&#xff1a; 批量插入&#xff1a; 而不是逐条插入&#xff0c;可以使用单个INSERT语句插入多行数据。例如&#xff1a; INSERT INTO table_name (col1, col2) V…...

【密码学】什么是密码?什么是密码学?

一、密码的定义 根据《中华人民共和国密码法》对密码的定义如下&#xff1a; 密码是指采用特定变换的方法对信息等进行加密保护、安全认证的技术、产品和服务。 二、密码学的定义 密码学是研究编制密码和破译密码的技术科学。由定义可以知道密码学分为两个主要分支&#x…...

k8s record 20240703

1. containerd 它不用于直接和开发人员互动&#xff0c;在这方面不和docker竞争 containerd的用时最短&#xff0c;性能最好。 containerd 是容器的生命周期管理&#xff0c;容器的网络管理等等&#xff0c;真正让容器运行需要runC containerd 是一个独立的容器运行时&am…...

Ansible常用模块

华子目录 Ansible四个命令模块1.组成2.特点3.区别3.1command、shell模块3.2raw模块 4.command模块4.1参数表4.2free_form参数 5.shell模块5.1作用5.2例如 6.script模块6.1示例 7.raw模块7.1参数7.2示例 文件操作模块1.file模块1.1参数1.2示例 2.copy模块2.1参数 Ansible四个命令…...

【JavaScript脚本宇宙】提升用户体验:探索 JavaScript 库中的浏览器特性支持检测

深入探讨JavaScript库&#xff1a;功能、配置与应用场景 前言 在现代的Web开发中&#xff0c;JavaScript库扮演着至关重要的角色&#xff0c;帮助开发人员简化代码、提高效率、实现更好的用户体验。本文将探讨几个常用的JavaScript库&#xff0c;包括模块加载库、数据绑定库和…...

深度学习:C++和Python如何对大图进行小目标检测

最近在医美和工业两条线来回穿梭&#xff0c;甚是疲倦&#xff0c;一会儿搞搞医美的人像美容&#xff0c;一会儿搞搞工业的检测&#xff0c;最近新接的一个项目&#xff0c;关于瑕疵检测的&#xff0c;目标图像也并不是很大吧&#xff0c;需要放大后&#xff0c;才能看见细小的…...

Eureka从入门到精通面试题及答案参考

什么是Eureka?它在微服务架构中扮演什么角色? Eureka是Netflix开源的一款基于REST的服务发现组件,它主要应用于构建分布式系统中的服务注册与发现。在微服务架构中,Eureka扮演着至关重要的角色,它让微服务架构中的各个服务实例能够互相发现、相互调用,从而实现了服务之间…...

io流 多线程

目录 一、io流 1.什么是io流 2.流的方向 i.输入流 ii.输出流 3.操作文件的类型 i.字节流 1.拷贝 ii.字符流 ​3.字符流输出流出数据 4.字节流和字符流的使用场景 5.练习 6.缓冲流 1.字节缓冲流拷贝文件 2.字符缓冲流特有的方法 1.方法 2.总结 7.转换流基本用法…...

人工智能、机器学习、神经网络、深度学习和卷积神经网络的概念和关系

人工智能&#xff08;Artificial Intelligence&#xff0c;缩写为AI&#xff09;--又称为机器智能&#xff0c;是研究、开发用于模拟、延伸和扩展人的智能的理论、方法、技术及应用系统的一门新的技术科学。 人工智能是智能学科重要的组成部分&#xff0c;它企图了解智能的实质…...

对话大模型Prompt是否需要礼貌点?

大模型相关目录 大模型&#xff0c;包括部署微调prompt/Agent应用开发、知识库增强、数据库增强、知识图谱增强、自然语言处理、多模态等大模型应用开发内容 从0起步&#xff0c;扬帆起航。 基于Dify的QA数据集构建&#xff08;附代码&#xff09;Qwen-2-7B和GLM-4-9B&#x…...

【驱动篇】龙芯LS2K0300之ADC驱动

实验目的 由于LS2K0300久久派开发板4.19内核还没有现成可用的ADC驱动&#xff0c;但是龙芯官方的5.10内核已经提供了ADC驱动&#xff0c;想要在4.19内核使用ADC就要参考5.10内核移植驱动&#xff0c;本次实验主要是关于ADC驱动的移植和使用 驱动移植 主要的驱动代码主要有3个…...

Python入门 2024/7/3

目录 for循环的基础语法 遍历字符串 练习&#xff1a;数一数有几个a range语句 三个语法 语法1 语法2 语法3 练习&#xff1a;有几个偶数 变量作用域 for循环的嵌套使用 打印九九乘法表 发工资案例 continue和break语句 函数的基础定义语法 函数声明 函数调用 …...

Go 语言 Map(集合)

Go 语言 Map(集合) Map 是 Go 语言中一种非常重要的数据结构,它用于存储键值对。在 Go 中,Map 是一种无序的键值对的集合,其中每个键都是唯一的,而值则可以是任何类型。Map 是 Go 语言的内置类型,使用起来非常方便,同时也是许多 Go 程序中不可或缺的一部分。 Map 的声明…...

SpringCloud学习Day7:Seata

概念 Seata是一款开源的分布式事务解决方案&#xff0c;致力于在微服务架构下提供高性能和简单易用的分布式事务服务 工作流程 TC以Seata服务器形式独立部署&#xff0c;TM和RM则是以Seata Client的形式集成在微服务中运行...

【HarmonyOS 5.0】DevEco Testing:鸿蒙应用质量保障的终极武器

——全方位测试解决方案与代码实战 一、工具定位与核心能力 DevEco Testing是HarmonyOS官方推出的​​一体化测试平台​​&#xff0c;覆盖应用全生命周期测试需求&#xff0c;主要提供五大核心能力&#xff1a; ​​测试类型​​​​检测目标​​​​关键指标​​功能体验基…...

DAY 47

三、通道注意力 3.1 通道注意力的定义 # 新增&#xff1a;通道注意力模块&#xff08;SE模块&#xff09; class ChannelAttention(nn.Module):"""通道注意力模块(Squeeze-and-Excitation)"""def __init__(self, in_channels, reduction_rat…...

JVM垃圾回收机制全解析

Java虚拟机&#xff08;JVM&#xff09;中的垃圾收集器&#xff08;Garbage Collector&#xff0c;简称GC&#xff09;是用于自动管理内存的机制。它负责识别和清除不再被程序使用的对象&#xff0c;从而释放内存空间&#xff0c;避免内存泄漏和内存溢出等问题。垃圾收集器在Ja…...

学校招生小程序源码介绍

基于ThinkPHPFastAdminUniApp开发的学校招生小程序源码&#xff0c;专为学校招生场景量身打造&#xff0c;功能实用且操作便捷。 从技术架构来看&#xff0c;ThinkPHP提供稳定可靠的后台服务&#xff0c;FastAdmin加速开发流程&#xff0c;UniApp则保障小程序在多端有良好的兼…...

OkHttp 中实现断点续传 demo

在 OkHttp 中实现断点续传主要通过以下步骤完成&#xff0c;核心是利用 HTTP 协议的 Range 请求头指定下载范围&#xff1a; 实现原理 Range 请求头&#xff1a;向服务器请求文件的特定字节范围&#xff08;如 Range: bytes1024-&#xff09; 本地文件记录&#xff1a;保存已…...

Spring Boot面试题精选汇总

&#x1f91f;致敬读者 &#x1f7e9;感谢阅读&#x1f7e6;笑口常开&#x1f7ea;生日快乐⬛早点睡觉 &#x1f4d8;博主相关 &#x1f7e7;博主信息&#x1f7e8;博客首页&#x1f7eb;专栏推荐&#x1f7e5;活动信息 文章目录 Spring Boot面试题精选汇总⚙️ **一、核心概…...

关于 WASM:1. WASM 基础原理

一、WASM 简介 1.1 WebAssembly 是什么&#xff1f; WebAssembly&#xff08;WASM&#xff09; 是一种能在现代浏览器中高效运行的二进制指令格式&#xff0c;它不是传统的编程语言&#xff0c;而是一种 低级字节码格式&#xff0c;可由高级语言&#xff08;如 C、C、Rust&am…...

什么?连接服务器也能可视化显示界面?:基于X11 Forwarding + CentOS + MobaXterm实战指南

文章目录 什么是X11?环境准备实战步骤1️⃣ 服务器端配置(CentOS)2️⃣ 客户端配置(MobaXterm)3️⃣ 验证X11 Forwarding4️⃣ 运行自定义GUI程序(Python示例)5️⃣ 成功效果![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/55aefaea8a9f477e86d065227851fe3d.pn…...

学习STC51单片机32(芯片为STC89C52RCRC)OLED显示屏2

每日一言 今天的每一份坚持&#xff0c;都是在为未来积攒底气。 案例&#xff1a;OLED显示一个A 这边观察到一个点&#xff0c;怎么雪花了就是都是乱七八糟的占满了屏幕。。 解释 &#xff1a; 如果代码里信号切换太快&#xff08;比如 SDA 刚变&#xff0c;SCL 立刻变&#…...

如何在网页里填写 PDF 表格?

有时候&#xff0c;你可能希望用户能在你的网站上填写 PDF 表单。然而&#xff0c;这件事并不简单&#xff0c;因为 PDF 并不是一种原生的网页格式。虽然浏览器可以显示 PDF 文件&#xff0c;但原生并不支持编辑或填写它们。更糟的是&#xff0c;如果你想收集表单数据&#xff…...