当前位置: 首页 > 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的形式集成在微服务中运行...

【入坑系列】TiDB 强制索引在不同库下不生效问题

文章目录 背景SQL 优化情况线上SQL运行情况分析怀疑1:执行计划绑定问题?尝试:SHOW WARNINGS 查看警告探索 TiDB 的 USE_INDEX 写法Hint 不生效问题排查解决参考背景 项目中使用 TiDB 数据库,并对 SQL 进行优化了,添加了强制索引。 UAT 环境已经生效,但 PROD 环境强制索…...

OkHttp 中实现断点续传 demo

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

Angular微前端架构:Module Federation + ngx-build-plus (Webpack)

以下是一个完整的 Angular 微前端示例&#xff0c;其中使用的是 Module Federation 和 npx-build-plus 实现了主应用&#xff08;Shell&#xff09;与子应用&#xff08;Remote&#xff09;的集成。 &#x1f6e0;️ 项目结构 angular-mf/ ├── shell-app/ # 主应用&…...

LLMs 系列实操科普(1)

写在前面&#xff1a; 本期内容我们继续 Andrej Karpathy 的《How I use LLMs》讲座内容&#xff0c;原视频时长 ~130 分钟&#xff0c;以实操演示主流的一些 LLMs 的使用&#xff0c;由于涉及到实操&#xff0c;实际上并不适合以文字整理&#xff0c;但还是决定尽量整理一份笔…...

C# 表达式和运算符(求值顺序)

求值顺序 表达式可以由许多嵌套的子表达式构成。子表达式的求值顺序可以使表达式的最终值发生 变化。 例如&#xff0c;已知表达式3*52&#xff0c;依照子表达式的求值顺序&#xff0c;有两种可能的结果&#xff0c;如图9-3所示。 如果乘法先执行&#xff0c;结果是17。如果5…...

pycharm 设置环境出错

pycharm 设置环境出错 pycharm 新建项目&#xff0c;设置虚拟环境&#xff0c;出错 pycharm 出错 Cannot open Local Failed to start [powershell.exe, -NoExit, -ExecutionPolicy, Bypass, -File, C:\Program Files\JetBrains\PyCharm 2024.1.3\plugins\terminal\shell-int…...

华为OD最新机试真题-数组组成的最小数字-OD统一考试(B卷)

题目描述 给定一个整型数组,请从该数组中选择3个元素 组成最小数字并输出 (如果数组长度小于3,则选择数组中所有元素来组成最小数字)。 输入描述 行用半角逗号分割的字符串记录的整型数组,0<数组长度<= 100,0<整数的取值范围<= 10000。 输出描述 由3个元素组成…...

【安全篇】金刚不坏之身:整合 Spring Security + JWT 实现无状态认证与授权

摘要 本文是《Spring Boot 实战派》系列的第四篇。我们将直面所有 Web 应用都无法回避的核心问题&#xff1a;安全。文章将详细阐述认证&#xff08;Authentication) 与授权&#xff08;Authorization的核心概念&#xff0c;对比传统 Session-Cookie 与现代 JWT&#xff08;JS…...

[USACO23FEB] Bakery S

题目描述 Bessie 开了一家面包店! 在她的面包店里&#xff0c;Bessie 有一个烤箱&#xff0c;可以在 t C t_C tC​ 的时间内生产一块饼干或在 t M t_M tM​ 单位时间内生产一块松糕。 ( 1 ≤ t C , t M ≤ 10 9 ) (1 \le t_C,t_M \le 10^9) (1≤tC​,tM​≤109)。由于空间…...

车载诊断架构 --- ZEVonUDS(J1979-3)简介第一篇

我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 做到欲望极简,了解自己的真实欲望,不受外在潮流的影响,不盲从,不跟风。把自己的精力全部用在自己。一是去掉多余,凡事找规律,基础是诚信;二是…...