【Redis 开发】一人一单,超卖问题(悲观锁,乐观锁,分布式锁)

  • 悲观锁
  • 乐观锁
      • 第一种:版本号法
      • 第二种:CAS法
        • 实现乐观锁
      • 悲观锁与乐观锁的比较
  • 一人一单
  • 分布式锁
    • Redis实现分布式锁

悲观锁

认为线程问题一定会发生,因此在操作数据库之前先获取锁,确保线程串行执行,例如Synchronized,Lock都属于悲观锁

乐观锁

认为线程安全问题不一定会发生,因此不加锁,只有在更新数据的时候去判断有没有其他线程对数据做了修改

  1. 如果没有修改则认为是安全的,自己才更新数据
  2. 如果已经被其它线程修改说明发生了安全问题,此时可以重试或异常

乐观锁的关键是判断之前查询到的数据是否被修改过,有两种方法:

第一种:版本号法

就是在商品上添加版本号,一个线程查询用户的时候查询到id和版本号信息,当他需要进行修改数据的时候进行对比现在的版本号看有没有发生变化马,如果有就停止操作,并重新开始,如果没有则修改数据并将版本号加一,每个线程都执行此操作

第二种:CAS法

CAS法就是在版本号法上面做出的微调,将监控版本号修改为直接监控库存就行

实现乐观锁

就是在扣减库存的时候加上一个条件。判断库存有没有发生变化

boolean success = seckillVoucherService.update().setSql("Stock=stock-1").eq("voucher_id",voucherId).gt("stock",0).update();

但是这样请求的失败率太高,我们可以进行稍微的修改,将判断条件库存大于0就行

悲观锁与乐观锁的比较

悲观锁:
优点:简单粗暴
缺点: 性能一般
乐观锁:
优点:性能好
缺点: 存在成功率低的问题

一人一单

超卖问题一般对于秒杀一个商品时所采用的技术,但是对于秒杀商品这种东西,一般一个用户只能够买一个,下一单

那么如何实现一人一单的问题呢:
就是在下单的时候,在订单数据库中进行查询如果该用户已经存在单子,那么会返回异常,如果在库中没有该用户,在创建新的订单,注意在创建新的订单之前需要使用悲观锁,防止多线程问题

注意:这里只能使用悲观锁,因为使用乐观锁无法进行判断

将从查询库中的信息开始到创建新的数据,封装在一个方法中,使用悲观锁synchronized并在该方法上添加事务

分布式锁

上述的乐观锁在进行用户并发中防止一个用户多次进行买单的处理,这只解决了单一服务器的多并发问题,当服务器处在集群中时,这个锁是锁不住的

原因:在多个集群中就会有多个jvm下的锁监视器,这些锁监视器只会监控本服务器下的悲观锁

所以为了控制集群下的多线程问题,我们采取分布式锁

那么什么是分布式锁:

就是多个服务器共用一个锁监视器,在同一个锁监视器中进行锁的监视

分布式锁的核心是实现多进程间的互斥,而满足这一点的方式有很多:
在这里插入图片描述

这里我们主要通过Redis实现分布式锁机制:

Redis实现分布式锁

实现和前面的讲的缓存击穿是所使用的方法类似
在Redis客户端模拟实现
set lock thread1 EX 10 NX
这样就会保证设置互斥和释放锁的原子性

多线程访问访问多集群的分布式锁工作流程:
在这里插入图片描述

  • 实现

首先定义一个锁的接口,实现该接口,利用Redis实现分布式锁功能

public interface ILock {/*** 尝试获取锁* @param timeoutSec* @return*/boolean tryLock(long timeoutSec);/*** 释放锁*/void unlock();
}

实现上述接口进行Redis操作

public class SimpleRedisLock implements ILock{private String name;private StringRedisTemplate stringRedisTemplate;public SimpleRedisLock(String name, StringRedisTemplate stringRedisTemplate) {this.name = name;this.stringRedisTemplate = stringRedisTemplate;}private static final String key_prefix="lock:";@Overridepublic boolean tryLock(long timeoutSec) {//获取线程的标识long id = Thread.currentThread().getId();Boolean aBoolean = stringRedisTemplate.opsForValue().setIfAbsent(key_prefix + name, id + "", timeoutSec, TimeUnit.SECONDS);//自动拆箱的返回return Boolean.TRUE.equals(aBoolean);}@Overridepublic void unlock() {//释放锁stringRedisTemplate.delete(key_prefix+name);}
}

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

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

相关文章

【Leetcode】vector刷题

🔥个人主页:Quitecoder 🔥专栏:Leetcode刷题 目录 1.只出现一次的数字2.杨辉三角3.删除有序数组中的重复项4.只出现一次的数字II5.只出现一次的数字III6.电话号码的字母组合 1.只出现一次的数字 题目链接:136.只出现一…

HCIP-Datacom-ARST必选题库_01_ACL【7道题】

一、单选 1.下面是一台路由器的部分配置,关于该配置描述正确的是: 源地址为1.1.1.1的数据包匹配第一条ACL语句rule 0,匹配规则为允许 源地址为1.1.1.3的数据包匹配第三条ACL语句rule 2,匹配规则为拒绝 源地址为1.1.1.4的数据包匹配第四条ACL语句rule 3,匹配规则为允…

Scala 05 —— 函数式编程底层逻辑

Scala 05 —— 函数式编程底层逻辑 该文章来自2023/1/14的清华大学交叉信息学院助理教授——袁洋演讲。 文章目录 Scala 05 —— 函数式编程底层逻辑函数式编程假如...副作用是必须的?函数的定义函数是数据的函数,不是数字的函数如何把业务逻辑做成纯函…

python爬虫学习------scrapy第二部分(第三十天)

🎈🎈作者主页: 喔的嘛呀🎈🎈 🎈🎈所属专栏:python爬虫学习🎈🎈 ✨✨谢谢大家捧场,祝屏幕前的小伙伴们每天都有好运相伴左右,一定要天天…

底层逻辑(1) 是非对错

底层逻辑(1) 是非对错 关于本书 这本书的副标题叫做:看清这个世界的底牌。让我想起电影《教父》中的一句名言:花半秒钟就看透事物本质的人,和花一辈子都看不清事物本质的人,注定是截然不同的命运。 如果你看过梅多丝的《系统之美…

数据挖掘实验(Apriori,fpgrowth)

Apriori:这里做了个小优化,比如abcde和adcef自连接出的新项集abcdef,可以用abcde的位置和f的位置取交集,这样第n项集的计算可以用n-1项集的信息和数字本身的位置信息计算出来,只需要保存第n-1项集的位置信息就可以提速…

2024年巴黎奥运会临近,中国义乌又爆弹了?网友:这就是硬核实力

奥运订单热潮涌动,中国制造不可或缺 随着巴黎奥运会脚步的日益临近,中国义乌再次聚焦全球视野。 近日,国货探访浙江义乌国际商贸城,发现众多蕴含法国元素的商品被置于显眼位置,吸引众多采购商纷至沓来,争…

android脱壳:一种使用native进行抽取壳脱壳的方法,native版本的frida-fart

前言 写rxposed的时候,搞了很多模块,其中有一个远程调用脱壳的,但是当时使用的是rmi远程调用,因为一些问题无法使用,可能是对抗问题,也有可能是技术问题,所以我又换了一种远程调用方式。 概述…

云原生的基石:containerd引领未来容器发展趋势

文章目录 一、Containerd简介:容器技术的心脏二、Containerd核心原理解析三、Containerd与Docker的关系四、Containerd在云原生应用部署中的作用五、Containerd的扩展性和插件机制六、Containerd的安全特性七、Containerd的性能优化八、Containerd的社区和生态系统九…

【51单片机项目】基于51单片机自制多功能小键盘/模拟USB键盘【附源码】(STC89C52RC+CH9328)

目录 一、效果展示 二、创作灵感 三、硬件电路 注意事项 工作原理 四、源码 main.c 五、附录 CH9328工作原理 CH9328的模式选择 ​编辑 全键盘键码值表 参考链接 一、效果展示 该小键盘具有三种功能: 1、自动输入开机密码 2、每隔一段时间自动按下ct…

通用大模型研究重点之五:llama family

LLAMA Family decoder-only类型 LLaMA(Large Language Model AI)在4月18日公布旗下最大模型LLAMA3,参数高达4000亿。目前meta已经开源了80亿和700亿版本模型,主要升级是多模态、长文本方面工作。 模型特点:采用标准的…

Unreal Engine创建Plugin

打开UE工程,点击编辑,选择插件 点击“新插件”按钮,选择“空白选项”填入插件名字"MultiPlayerPlugin",填入插件作者、描述,点击“创建插件”按钮打开C工程,即可看到插件目录,编译C工…

【网络安全】安全事件管理处置 — 安全事件处置思路指导

专栏文章索引:网络安全 有问题可私聊:QQ:3375119339 目录 一、处理DDOS事件 1.准备工作 2.预防工作 3.检测与分析 4.限制、消除 5.证据收集 二、处理恶意代码事件 1.准备 2.预防 3.检测与分析 4.限制 5.证据收集 6.消除与恢复 …

游戏新手村18:游戏广告渠道与广告形式

上文我们说到,渠道为王,渠道可以为我们带来流量和用户,进而带来收入。我们可以通过哪些渠道导入用户呢?每个渠道有哪些优劣呢?在进行游戏营销推广的时候我们该如何选择呢? 根据付费性质,我们可…

鸿蒙ArkUI实战开发-如何通过上下滑动实现亮度和音量调节

场景说明 在音视频应用中通常可以通过上下滑动来调节屏幕亮度和音量大小,本例即为大家介绍如何实现上述UI效果。 说明: 由于当前亮度和音量调节功能仅对系统应用开发,所以本例仅讲解UI效果的实现。 效果呈现 本例效果如下: 当在…

iOS - 多线程-GCD-队列组

文章目录 iOS - 多线程-GCD-队列组1. 队列组1.1 基本使用步骤 iOS - 多线程-GCD-队列组 开发过程中,有时候想实现这样的效果 多个任务并发执行所有任务执行完成后,进行下一步处理(比如回到主线程刷新UI) 1. 队列组 可以使用GC…

区间图着色问题:贪心算法设计及实现

区间图着色问题:贪心算法设计及实现 1. 问题定义2. 贪心算法设计2.1 活动排序2.2 分配教室2.3 算法终止 3. 伪代码4. C语言实现5. 算法分析6. 结论7. 参考文献 在本文中,我们将探讨如何使用贪心算法解决一个特定的资源分配问题,即区间图着色问…

ruby 配置代理 ip(核心逻辑)

在 Ruby 中配置代理 IP,可以通过设置 Net::HTTP 类的 Proxy 属性来实现。以下是一个示例: require net/http// 获取代理Ip:https://www.kuaidaili.com/?refrg3jlsko0ymg proxy_address 代理IP:端口 uri URI(http://www.example.com)Net:…

【002_音频开发_基础篇_Linux音频架构简介】

002_音频开发_基础篇_Linux音频架构简介 文章目录 002_音频开发_基础篇_Linux音频架构简介创作背景Linux 音频架构ALSA 简介ASoC 驱动硬件架构软件架构MachinePlatformCodec ASoC 驱动 PCMALSA设备文件结构 ALSA 使用常用概念alsa-libALSA Open 流程ALSA Write 流程2种写入方法…

Android Studio查看viewtree

前言:之前开发过程一直看的是手机上开发者选项中的显示布局边界,开关状态需要手动来回切换,今天偶然在Android Studio中弄出了布局树觉得挺方便的。