Redis应用之二分布式锁2

一、前言

前一篇 Redis应用之二分布式锁  我们介绍了使用SETNX来实现分布式锁,并且还遗留了一个Bug,今天我们对代码进行优化,然后介绍一下Redisson以及数据库的乐观锁悲观锁怎么用。

二、SetNX分布式锁优化后代码

RedisService.java

InventoryMgrImpl.java

将代码部署在两台机器,库存设置为10000, set "inventory:9321785256118"  10000,然后Jemter创建两个线程组,每个线程组起500个线程,循环执行10次,结果库存值为0,没有产生并发问题。注(这里每一次调用扣减一个库存)。

注意点

1、设置锁的超时时间,超时时间不能设置太短,一定要比业务代码执行耗时最长的时间再大一些,一般设置为3秒差不多,上一篇文章用了Redis分布式锁还产生问题的原因就是因为超时时间设置太短造成的,业务代码还未执行完,锁就失效被另外一个线程持有然后在并发量大的情况就产生问题了。另外老版本Redis的SetNX好像是不能设置超时时间,这个就必须自己去控制超时以避免死锁。

2、代码中当获取锁失败立即重新去获取这个会对redis造成冲击,可以加入适当的休眠时间。

三、使用Redisson实现Redis分布式锁

Redisson是一个基于Redis扩展库,提供了很多具有分布式环境特性的常用工具类,我们这里用来使用它分布式锁机制。

1、加入依赖包

2、配置类

3、代码中获取锁

用100个线程两台机器压测,未产生并发问题。

注:高版本JDK(比如JDK17)Redisson运行时报错,原因未确认。

以上不管是自己直接调用SetNX,还是用Redisson做分布式锁都是基于单台Redis的,如果是集群Redis会更复杂一些。

四、数据库锁

数据库锁也分为乐观锁和悲观锁,这种方案在传统软件公司会采用比较多一些,互联网公司一般不太采用数据库的特性去做事情,主要是数据库负载相对来讲比较大,会尽量避免。

1、乐观锁

认为数据一般不会发生冲突,在数据提交更新时才会去检查数据是否冲突,如果冲突不执行返回错误。

具体实现:通过给表加一个version字段来实现,当读取数据时,将version字段的值一起读出,数据每更新一次,对此version值加一。当我们提交更新的时候,判断当前version与开始取出来的版本值大小是否相等,如果相等,则予以更新,否则认为出现并发问题不更新数据,让用户重新操作。

创建库存表

SpringBoot整合JDBC

InventoryManagerDB.java

不用数据库锁,Jmeter开启两组线程,每组1个线程,循环500次,最终库存数据是208,肯定会产生并发问题。

代码中加上乐观锁

1、数据库增加version字段

2、InventoryManagerDB.java

Jmeter开启两组线程,每组1个线程,循环500次,最终库存数如下

这说明有307次变更库存是失败的,693次变更成功,但没有发生并发问题,因为直接告诉用户失败了或者让用户采用重试机制。

2、悲观锁

对数据的冲突采取悲观的态度,也就是假设数据肯定会冲突,所以在数据开始读取的时候,就把数据锁定住,此时当其他事务如果要更新此条记录就会因为不能获得锁而阻塞。

注意:这里查询的时候用主键然后加上for update锁定这条记录,并且该方法要加上@Transactional事务控制,如果不是使用主键可能就把整张表锁住了。

Jmeter开启两组线程,每组50个线程,循环10次,最终库存数据是0,未产生并发问题。

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

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

相关文章

模拟散列表(哈希表拉链法)

维护一个集合,支持如下几种操作: I x,插入一个整数 x;Q x,询问整数 x 是否在集合中出现过; 现在要进行 N 次操作,对于每个询问操作输出对应的结果。 输入格式 第一行包含整数 N,…

SpringBoot3+Vue3+Mysql+Element Plus完成数据库存储blob类型图片,前端渲染后端传来的base64类型图片

前言 如果你的前后端分离项目采用SpringBoot3Vue3Element Plus,且在没有OSS(对象存储)的情况下,使用mysql读写图片(可能不限于图片,待测试)。 耗时三天,在踩了无数雷后&#xff0c…

Python基础入门----使用Pipenv工具时产生的Pipfile和Pipfile.lock文件有什么区别以及有什么作用

文章目录 PipfilePipfile.lock实操示例当我们使用 Pipenv 工具进行 Python 项目的依赖管理时,会遇到两个重要的文件:Pipfile 和 Pipfile.lock。这两个文件在项目中扮演着不同但又相互补充的角色。接下来,我将详细介绍这两个文件的区别和作用,并提供一些具体的使用示例。 P…

并查集详解(附例题和模板)

一、并查集 (1)处理问题的类型 1.将两个集合合并 2.询问两个元素是否在一个集合当中 询问 1.fa[x]a; 2.if(fa[x]fa[y]) o(1) 在o(1)的复杂度内进行两个操作 (2)基本原理 基本原理:每个集合用一棵树来表示&#…

Redis 5大数据类型命令解读

目录 Redis key的命令 1、redis字符串(String) 2、redis列表(List) 3、redis哈希表(Hash) 4、redis集合(Set) 5、redis有序集合(ZSet) Redis 命令网站:redis中文文档 Redis key的命令 命令说明示例keys *查看当前库所有的keykeys *…

uniapp——项目day04

购物车页面——商品列表区域 渲染购物车商品列表的标题区域 1. 定义如下的 UI 结构: 2.美化样式 渲染商品列表区域的基本结构 1. 通过 mapState 辅助函数,将 Store 中的 cart 数组映射到当前页面中使用: import badgeMix from /mixins/tab…

Linux shell编程学习笔记25:tty

1 tty的由来 在 1830 年代和 1840 年代,开发了称为电传打字机(teletypewriters)的机器,这些机器可以将发件人在键盘上输入的消息“沿着线路”发送在接收端并打印在纸上。 电传打字机的名称由teletypewriters, 缩短为…

R语言——taxize(第一部分)

ropensci 系列之 taxize (中译手册) taxize 包1. taxize支持的网络数据源简介目前支持的API:针对Catalogue of Life(COL) 2. 浅尝 taxize 的一些使用例子2.1. **从NCBI上获取唯一的分类标识符**2.2. **获取分类信息**2…

【Qt之QWizard】使用1

QWizard使用 描述方法枚举:enum QWizard::WizardButton枚举:enum QWizard::WizardOption枚举:enum QWizard::WizardStyle枚举:enum QWizard::WizardPixmap常用成员方法槽函数信号 示例设置标题添加page页设置按钮文本设置自定义按…

基于SpringBoot+Vue的宿舍管理系统

基于SpringBootVue的学生宿舍管理系统的设计与实现~ 开发语言:Java数据库:MySQL技术:SpringBootMyBatisVue工具:IDEA/Ecilpse、Navicat、Maven 系统展示 主页 宿舍公告 登录界面 管理员界面 维修人员 商家界面 学生界面 摘要 摘…

No202.精选前端面试题,享受每天的挑战和学习

🤍 前端开发工程师(主业)、技术博主(副业)、已过CET6 🍨 阿珊和她的猫_CSDN个人主页 🕠 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 🍚 蓝桥云课签约作者、已在蓝桥云课上架的前后端实战课程《Vue.js 和 Egg.js 开发企业级健康管理项目》、《带你从入…

Python爬虫——入门爬取网页数据

目录 前言 一、Python爬虫入门 二、使用代理IP 三、反爬虫技术 1. 间隔时间 2. 随机UA 3. 使用Cookies 四、总结 前言 本文介绍Python爬虫入门教程,主要讲解如何使用Python爬取网页数据,包括基本的网页数据抓取、使用代理IP和反爬虫技术。 一、…