(六)库存超卖案例实战——使用mysql分布式锁解决“超卖”问题

前言

本节内容是关于使用分布式锁解决并发访问“超卖”问题的最终篇,在前面的章节中我们介绍了使用mysql的行锁、乐观锁、悲观锁解决并发访问导致的超卖问题,存在的问题是行锁、乐观锁、悲观锁不太灵活,需要和具体的业务耦合到一起,不利于使用,本节内容我们通过mysql的唯一索引特性,数据不能重复插入,达到独占排它的基本要求,实现通用的分布式锁功能。

正文

  • 创建表app_lock,用于实现分布式锁

- app_lock表

CREATE TABLE `app_lock` (`id` bigint NOT NULL AUTO_INCREMENT COMMENT 'ID',`lock_name` varchar(255) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '锁名称',`class_name` varchar(255) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '类名',`method_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '方法名称',`server_ip` varchar(255) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '服务器IP',`thread_name` varchar(255) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '线程名称',`create_time` datetime DEFAULT NULL COMMENT '创建时间',`expire_time` datetime DEFAULT NULL COMMENT '过期时间',`remark` varchar(255) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '备注',PRIMARY KEY (`id`),UNIQUE KEY `idx_lock_name` (`lock_name`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='应用锁';

PS:lock_name为锁名称,建立唯一索引,保证锁的唯一性,server_ip主机信息和thread_name线程号,可以将分布式锁扩展为可重入锁,expire_time过期时间,可通过定时任务或者消息中间键,自动释放锁。

  • 表app_lock实体类创建 
package com.ht.atp.plat.entity;import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
import java.time.LocalDateTime;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.Getter;
import lombok.Setter;@Data
@TableName("app_lock")
@ApiModel(value = "AppLock对象", description = "应用锁")
public class AppLock implements Serializable {private static final long serialVersionUID = 1L;@ApiModelProperty("ID")@TableId(value = "id", type = IdType.AUTO)private Long id;@ApiModelProperty("锁名称")@TableField("lock_name")private String lockName;@ApiModelProperty("类名")@TableField("class_name")private String className;@ApiModelProperty("方法名称")@TableField("method_name")private String methodName;@ApiModelProperty("服务器IP")@TableField("server_ip")private String serverIp;@ApiModelProperty("线程名称")@TableField("thread_name")private String threadName;@ApiModelProperty("创建时间")@TableField("create_time")private LocalDateTime createTime;@ApiModelProperty("过期时间")@TableField("expire_time")private LocalDateTime expireTime;@ApiModelProperty("备注")@TableField("remark")private String remark;}
  • 创建应用锁的加锁和解锁方法 

- 实现代码

package com.ht.atp.plat.service.impl;import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ht.atp.plat.entity.AppLock;
import com.ht.atp.plat.mapper.AppLockMapper;
import com.ht.atp.plat.service.AppLockService;
import org.springframework.stereotype.Service;@Service
public class AppLockServiceImpl extends ServiceImpl<AppLockMapper, AppLock> implements AppLockService {@Overridepublic void lock(AppLock appLock) {try {this.baseMapper.insert(appLock);} catch (Exception ex) {// 获取锁失败,则重试try {Thread.sleep(50);this.lock(appLock);} catch (InterruptedException e) {e.printStackTrace();}}}@Overridepublic void unlock(AppLock appLock) {this.baseMapper.deleteById(appLock.getId());}
}

- 通过自旋的方式加锁

- 解锁直接将锁删除

  • 实现扣减库存的业务代码 

- 实现代码

    @Autowiredprivate AppLockService appLockService;@Overridepublic void checkAndReduceStock() {AppLock appLock = new AppLock();appLock.setLockName("lock");appLock.setClassName(this.getClass().getName());appLock.setMethodName("checkAndReduceStock");appLock.setServerIp("127.0.0.1");appLock.setThreadName(Thread.currentThread().getName());appLock.setCreateTime(LocalDateTime.now());appLock.setExpireTime( LocalDateTime.now().plusSeconds(30));appLock.setRemark("这是一个测试用锁!");try {// 加锁appLockService.lock(appLock);// 查询库存WmsStock wmsStock = baseMapper.selectById(1L);// 验证库存大于0再扣减库存if (wmsStock != null && wmsStock.getStockQuantity() > 0) {wmsStock.setStockQuantity(wmsStock.getStockQuantity() - 1);baseMapper.updateById(wmsStock);}} catch (Exception e) {e.printStackTrace();} finally {// 解锁appLockService.unlock(appLock);}}

  • 启动7000、7001、7002服务器,并将库存设置为10000

 

  •  启动jmeter压测扣减库存接口

  • 最终压测结果

 - 库存扣减为:0

-  压测结果:平均响应时间3461ms,每秒钟的吞吐量为27,性能相比redis和zookeeper锁,性能相差不少。

  • 关于mysql分布式锁的几点总结 

- mysql数据库存在单点故障,一旦数据库宕机,将导致应用锁不可用,可通过搭建主备数据库保证高可用

- 没有实现自动释放锁:可通过定时任务扫描应用锁数据,如果过期时间小于当前时间,将锁删除掉;或者通过消息中间件去删除锁

- 锁是非重入的:可以通过使用主机信息、端口号、线程号等信息判断是否是同一个线程,如果是同一个线程,则锁可重入

- mysql数据库分布式锁性能一般,不及redis和zookeeper分布式锁,使用简单

结语

关于使用mysql分布式锁解决“超卖”问题的内容到这里就结束了,后会有期。。。。。。

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

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

相关文章

面试官【说一下移动端1px的解决方案】

文章目录 前言使用伪类和transform使用border-image使用box-shadow使用媒体查询及scale使用viewport单位使用图片或SVG后言 前言 hello world欢迎来到前端的新世界 &#x1f61c;当前文章系列专栏&#xff1a;前端系列文章 &#x1f431;‍&#x1f453;博主在前端领域还有很多…

再获5G RedCap能力认证!宏电5G RedCap工业智能网关通过中国联通5G物联网OPENLAB开放实验室测试验证

​近日&#xff0c;中国联通5G物联网OPENLAB开放实验室携手宏电股份完成5G RedCap工业智能网关端到端的测试验证&#xff0c;并颁发OPENLAB实验室面向RedCap终端的认证证书&#xff0c;为RedCap产业规模推广、全行业赋能打下坚实基础。 中国联通5G物联网OPENLAB开放实验室是中国…

为什么是LangChain?

文章目录 一、前言二、认识langchain1. langchain的主要组成2. 总览LangChain2. LangChain的六大核心模块1. Models&#xff1a;模型统一接口2. Prompts&#xff1a;管理 LLM 输入3. Chains&#xff1a;将 LLM 与其他组件相结合&#xff0c;执行多个chain4. Indexes&#xff1a…

使用LogBack替换Log4j

目录 1.删除log4j有关的依赖&#xff0c;添加logBack依赖 2.删除log4j配置文件&#xff0c;增加logback.xml配置文件 3.更改application.yml配置文件&#xff0c;log文件指向logback.xml 4.重启 1.删除log4j有关的依赖&#xff0c;添加logBack依赖 <dependency><gr…

掌动智能:云可观测性的主要特点及应用场景

云全景可观测性安全平台是一个跨架构、跨平台的可观测性方案&#xff0c;实现对云环境下的细粒度数据可视化&#xff0c;满足安全部门对云内部安全领域的多场景诉求&#xff0c;包括敏感数据动态监管、云网攻击回溯分析、攻击横移风险监控、云异常流量分析。本文将介绍掌动智能…

关于使用es数组的改变方式

一&#xff09;改变原数组的方法&#xff08;9个&#xff09; ES5&#xff1a; 1. pop() 删除一个数组中的最后的一个元素&#xff0c;并且返回这个元素。 2.shift() 删除数组的第一个元素&#xff0c;并返回这个元素。 3.push() 可向数组的末尾添加一个或多个元素&#xf…

【Nginx39】Nginx学习:upstream服务器组模块

Nginx学习&#xff1a;upstream服务器组模块 最后一个重点模块内容啦&#xff0c;感谢坚持到现在的你和我。总算是向大佬的道路上又前进了一步了。今天的内容主要是服务器组的配置&#xff0c;其实更直白点&#xff0c;就是 Nginx 负载均衡的配置模块。会不会有小伙伴不明白负载…

kubernetes集群编排(8)

k8s资源监控 资源限制 上传镜像 [rootk8s2 limit]# vim limit.yaml apiVersion: v1 kind: Pod metadata:name: memory-demo spec:containers:- name: memory-demoimage: stressargs:- --vm- "1"- --vm-bytes- 200Mresources:requests:memory: 50Milimits:memory: 100…

04-react基础知识-路由

一、react路由环境安装 使用指令&#xff1a;npm i --save react-router-dom type/react-router-dom进行react路由环境安装 二、引入路由 在main.jsx文件中引入该语句&#xff1a; import { createBrowserRouter, RouterProvider } from react-router-dom 定义一个变量rou…

【Java笔试强训】Day9(CM72 另类加法、HJ91 走方格的方案数)

CM72 另类加法 链接&#xff1a;另类加法 题目&#xff1a; 给定两个int A和B。编写一个函数返回AB的值&#xff0c;但不得使用或其他算数运算符。 题目分析&#xff1a; 代码实现&#xff1a; package Day9;public class Day9_1 {public int addAB(int A, int B) {// wr…

「Verilog学习笔记」使用子模块实现三输入数的大小比较

专栏前言 本专栏的内容主要是记录本人学习Verilog过程中的一些知识点&#xff0c;刷题网站用的是牛客网 分析 题目要求编写子模块实现两个输入数的大小比较并输出较小值&#xff0c;可以使用if-else语句实现。同时要求在主模块中实现三个输入数值的大小比较&#xff0c;假设三个…

【配置】如何在打包Spring Boot项目时按需使用日常、测试、预发、正式环境的配置文件

文章目录 前言1. 创建5个配置文件2. 在pom.xml文件中如下配置3. 在application.properties中加入环境变量 前言 在我们开发项目的时候&#xff0c;一般有四套环境&#xff1a;日常、测试、预发、正式。日常环境作为我们开发环境&#xff1b;测试环境给测试同学测试功能&#x…

AI诈骗的防范与应对:维护数字安全的责任

近年来&#xff0c;人工智能生成内容&#xff08;AIGC&#xff09;技术在各个领域都取得了显著的进展&#xff0c;为我们带来了更多的便捷和创新。然而&#xff0c;与此同时&#xff0c;这项技术也被不法分子滥用&#xff0c;用于实施各种形式的AI诈骗。这种威胁需要我们认真对…

​软考-高级-信息系统项目管理师教程 第四版【第21章-项目管理科学基础-思维导图】​

软考-高级-信息系统项目管理师教程 第四版【第21章-项目管理科学基础-思维导图】 课本里章节里所有蓝色字体的思维导图

抽象方法及接口的使用概念

abstract关键字 /* * 类和对象&#xff1a; * 类&#xff1a;一个概念&#xff0c;客观不存在的&#xff0c;或者认为是一个模板。 * 对象&#xff1a;看得见摸得着的真实存在的物体。 * 对象---类的过程&#xff0c;抽象 * 类---对象的过程&#xff0c;叫实例化 * 抽…

oracle查询前几条数据的方法

在Oralce中实现select top N&#xff1a;由于Oracle不支持select top 语句&#xff0c;所以在oracle中经常是用order by 跟rownum的组合来实现select top n的查询。 方法1&#xff1a; SELECT * FROM (SELECT * FROM EMP ORDER BY SAL DESC) WHERE ROWNUM < 5 --抽取处记录…

【elasticsearch+kibana基于windows docker安装】

创建网络&#xff1a;es和kibana容器互联 docker network create es-net加载镜像 docker pull elasticsearch:7.12.1运行 docker run -d --name es -p 9200:9200 -p 9300:9300 -e "discovery.typesingle-node" -e ES_JAVA_OPTS"-Xms512m -Xmx512m" -v $…

uni-app基于vue实现商城小程序

一、前言 参考“网易严选”小程序 项目采用传统vue项目结构&#xff0c;即uni-app打包和运行成小程序&#xff0c;使用HBuilder开发工具开发项目&#xff0c;通过运行启动“微信开发者工具”完成项目启动。 二、功能效果图 1.首页 2.分类 3.活动 4.我的 5.商品详情 6.购物车…

React中组件之间如何通信?

一、是什么 我们将组件间通信可以拆分为两个词&#xff1a; 组件通信 回顾Vue系列的文章&#xff0c;组件是vue中最强大的功能之一&#xff0c;同样组件化是React的核心思想 相比vue&#xff0c;React的组件更加灵活和多样&#xff0c;按照不同的方式可以分成很多类型的组件…

第五届泰迪杯数据分析技能赛B题源码图片分享

需要B题源码以及第六届带队”指导“请私信本人&#xff0c;团队包含技能赛双一等&#xff0c;数学建模省一&#xff0c;泰迪杯挖掘国一&#xff0c;研究生队友。 去年一等作品可视化图如下&#xff0c;私信获取源码