(六)库存超卖案例实战——使用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 {

    @Override
    public void lock(AppLock appLock) {
        try {
            this.baseMapper.insert(appLock);
        } catch (Exception ex) {
            // 获取锁失败,则重试
            try {
                Thread.sleep(50);
                this.lock(appLock);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

    }

    @Override
    public void unlock(AppLock appLock) {
        this.baseMapper.deleteById(appLock.getId());
    }
}

- 通过自旋的方式加锁

- 解锁直接将锁删除

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

- 实现代码

    @Autowired
    private AppLockService appLockService;

    @Override
    public 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.mfbz.cn/a/122428.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

数据结构与算法C语言版学习笔记(4)-栈与队列再回顾

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言&#xff1a;一、栈的定义&#xff1a;栈(stack)是限定仅在表尾进行插入和删除操作的线性表&#xff08;1&#xff09;栈是特殊的线性表&#xff08;2&#xff…

Sui学术研究奖公布,资助研究者探索人工智能、能源市场和区块链游戏

Sui基金会高兴地宣布首轮Sui学术研究奖&#xff08;SARAs&#xff09;的获奖者。SARAs计划提供资助&#xff0c;支持推动Sui区块链技术的研究。学术和研究界对我们的初次征集呈现出大量高质量的提案。 已接受的九个提案涵盖了各种主题&#xff0c;如token经济学、智能合约机制…

Java 设计模式——状态模式

目录 1.概述2.结构3.案例实现3.1.抽象状态类3.2.具体状态类3.3.上下文类3.4.测试 4.优缺点5.使用场景 1.概述 【例】通过按钮来控制一个电梯的状态&#xff0c;电梯有开门状态&#xff0c;关门状态&#xff0c;停止状态&#xff0c;运行状态。每一种状态改变&#xff0c;都有可…

银行APP虚拟金额软件,建设农业工商邮政余额生成器,易语言开源版

用易语言开发了一个虚拟余额装逼软件&#xff0c;可以生成虚拟的余额截图&#xff0c;就是APP端的截图&#xff0c;用的画板组件&#xff0c;但是生成出来的图片是非常高清的&#xff0c;软件里面因为图片是缩放状态&#xff0c;所以看起来有点失真的感觉&#xff0c;生成图片的…

Mysql进阶-视图篇

介绍 视图&#xff08;View&#xff09;是一种虚拟存在的表。视图中的数据并不在数据库中实际存在&#xff0c;行和列数据来自定义视图的查询中使用的表&#xff0c;并且是在使用视图时动态生成的。 通俗的讲&#xff0c;视图只保存了查询的SQL逻辑&#xff0c;不保存查询结果。…

汇编-EQU伪指令(数值替换)

EQU伪指令将一个符号名称与一个整数表达式或一个任意文本相关联&#xff0c; 它有3种格式 在第一种格式中&#xff0c; expression必须是一个有效的整数表达式。在第二种格式中&#xff0c; symbol是一个已存在的符号名称&#xff0c; 已经用或EQU定义过。在第三种格式中&…

想水目标检测sci论文的同学看过来:第一个用于目标检测的扩散模型

目标检测新范式&#xff01;在 COCO、CrowdHuman 和 LVIS上取得了良好的性能&#xff0c;尤其是跨不同场景的零样本迁移 本文提出了 DiffusionDet&#xff0c;这是一个新框架&#xff0c;它将目标检测制定为从噪声框到对象框的去噪扩散过程。 在训练阶段&#xff0c;目标框从真…

echart的tooltip显示不同的单位

效果 实现 在每个series中添加不同的 tooltip: { valueFormatter: function (value) { return value.toFixed(0) ‘A’; } }, 代码如下 var option {// grid: {// left: -13vw,//左边距72px// right: 32%,// bottom: 64%,// top:…

clickhouse通过java jdbc实现增删改查,保姆级教程

一、clickhouse是一款开源的用于在线分析处理查询(OLAP :Online Analytical Processing)MPP架构的列式存储数据库。 二、clickhouse可以做用户行为分析&#xff0c;流批一体 三、我们现在用java通过jdbc的方式来操作clickhouse 四、先安装clickhouse&#xff0c;安装资料自行…

通达OA V12版,引入thinkphp5.1框架,及获取session

通达OA V12版&#xff0c;引入thinkphp5.1框架 如下过程引入如下问题&#xff0c;按上述问题解决htmlentities(): charset cp936 not supported, assuming utf-8 内容绝对原创&#xff0c;希望对您有帮助。您的打赏&#xff0c;是让我持续更新的牛奶和面包 如下过程引入 在D:/…

有效降低数据库存储成本方案与实践 | 京东云技术团队

背景 随着平台的不断壮大&#xff0c;业务的不断发展&#xff0c;后端系统的数据量、存储所使用的硬件成本也逐年递增。从发展的眼光看&#xff0c;业务与系统要想健康的发展&#xff0c;成本增加的问题必须重视起来。目前业界普遍认同开源节流大方向&#xff0c;很多企业部门…

总结Kibana DevTools如何操作elasticsearch的常用语句

一、操作es的工具 ElasticSearch HeadKibana DevToolsElasticHQ 本文主要是总结Kibana DevTools操作es的语句。 二、搜索文档 1、根据ID查询单个记录 GET /course_idx/_doc/course:202、term 匹配"name"字段的值为"6789999"的文档 类似于sql语句中的等…

载波通讯电表的使用年限是多久?

随着科技的飞速发展&#xff0c;智能家居、物联网等概念逐渐深入人心&#xff0c;载波通讯电表作为一种新型的智能电表&#xff0c;凭借其低功耗、高可靠性、远程通讯等优点&#xff0c;广泛应用于居民用电、工业生产等领域。那么&#xff0c;载波通讯电表的使用年限是多久呢&a…

vTESTstudio的使用

vTESTstudio介绍 vTESTstudio是Vector公司专为ECU自动化测试而研发的测试用例编写软件&#xff0c;可用于从模型测试到系统确认的所有开发阶段。它集成了多种用例编辑方法&#xff0c;能有效提高测试人员对测试设计的效率、具有可复用性等优点。它支持Python作为测试编程语言&…

vtk夹角计算控件

开发环境&#xff1a; Windows 11 家庭中文版Microsoft Visual Studio Community 2019VTK-9.3.0.rc0vtk-example参考代码目的&#xff1a;学习与总结 demo解决问题&#xff1a;renderWindow中创建一个夹角测量控件&#xff0c;通过三个点确定一个夹角 典型的控件类继承关系&am…

第134届广交会圆满落幕,百华鞋业不负众望,载誉收官!

第134届广交会线下展在广州圆满落幕&#xff0c;交出了亮眼的成绩单。相比往届&#xff0c;本届广交会展览总面积扩至155万平方米&#xff0c;展位总数7.4万个&#xff0c;展区总数55个&#xff0c;参展企业28533家&#xff0c;均创历史新高。据央媒等相关报道&#xff0c;本届…

Ubuntu LTS 坚持 10 年更新不动摇

导读Linux 内核开发者 Jonathan Corbet 此前在欧洲开源峰会上宣布&#xff0c;LTS 内核的支持时间将从六年缩短至两年&#xff0c;原因在于缺乏使用和缺乏支持。稳定版内核维护者 Greg Kroah-Hartman 也表示 “没人用 LTS 内核”。 近日&#xff0c;Ubuntu 开发商 Canonical 发…

COOHOM通过采用亚马逊云科“专库专用”的方式,为云原生的构建提供稳定的数据支撑

全球化浪潮下&#xff0c;面对全球化业务发展带来的新需求与新挑战&#xff0c;越来越多的企业开启了云原生构建旅程&#xff0c;以推动业务系统快速迭代&#xff0c;为国际业务的拓展打下坚实的基础。COOHOM是杭州群核信息技术有限公司旗下的国际化品牌。为全球企业和个人提供…

taro(踩坑) npm run dev:weapp 微信小程序开发者工具预览报错

控制台报错信息&#xff1a; VM72:9 app.js错误: Error: module vendors-node_modules_taro_weapp_prebundle_chunk-JUEIR267_js.js is not defined, require args is ./vendors-node_modules_taro_weapp_prebundle_chunk-JUEIR267_js.js 环境&#xff1a; node 版本&#x…

KubeSphere v3.4.0 部署K8S Docker + Prometheus + grafana

KubeSphere v3.4.0 部署K8S 1、整体思路2、修改linux主机名3、 离线安装3.1 问题列表3.2 执行命令成功列表 1、整体思路 将KubeSphere v3.4.0 安装包传输到其中一台机器修改Linux主机名&#xff08;选取3台&#xff0c;修改为master01、master02、master03&#xff09;安装官方…
最新文章