分布式锁【 基于synchronized锁解决超卖问题、分布式锁解决方案、悲观锁实现的分布式锁】(二)-全面详解(学习总结---从入门到深化)

news2024/11/24 4:33:23

 

目录

 分布式锁问题_演示问题

 基于synchronized锁解决超卖问题

分布式锁解决方案

 分布式锁实现方案

 分布式锁解决方案_数据库悲观锁实现的分布式锁

 项目中使用for update


 

 分布式锁问题_演示问题

 启动订单服务9090

 启动订单服务9091

 

 创建两个SpringBoot服务

 启动Nginx服务

下载Nginx windows服务,官网http://nginx.org/en/download.html

 

 配置负载均衡

编辑nginx.conf文件添加负载均衡的配置。

upstream test{
      server localhost:9090 ;
      server localhost:9091 ;
   }
    
server {
        listen       80;
        server_name localhost;
    
        location / {
            proxy_pass http://test;
       }
}

启动Nginx服务

在nginx目录下面

 启动JMeter压测工具

添加线程组 -> HTTP请求 -> 察看结果树 -> 聚合报告

 设置Http请求参数

 查看库存数据

 查看订单数据

 基于synchronized锁解决超卖问题

 Spring进行了统一的抽象,形成了 PlatformTransactionManager事务管理器接口 , 事务的 提交、回滚等操作 全部交给它来实现。

事务功能的总体接口设计 

三个接口功能一句话总的来说事务管理器基于事务基础信息在操作 事务时候对事务状态进行更新。

 方法加锁

public synchronized String createOrder(Integer produceId, Integer purchaseNum) { }

声明事务管理器

@Autowired
private PlatformTransactionManager platformTransactionManager;
@Autowired
private TransactionDefinition transactionDefinition;

手动创建事务

TransactionStatus transaction = platformTransactionManager.getTransaction(transactionDefinition);

手动提交事务

    /**
     * 创建订单
     *
     * @param produceId   商品id
     * @param purchaseNum 购买数量
     * @return
     */
    @Override
    public synchronized String createOrder(Integer produceId, Integer purchaseNum) {
        TransactionStatus transaction = platformTransactionManager.getTransaction(trans
actionDefinition);
        // 1、根据商品id获取商品信息
        Product product = productMapper.selectById(produceId);
        // 2、判断商品是否存在
        if (product == null) {
          platformTransactionManager.rollback(transaction);
            throw new RuntimeException("购买商品不存在");
       }
         log.info(Thread.currentThread().getName() + "库存数量" + product.getCount());
        // 3、校验库存
        if (purchaseNum > product.getCount()) {
           platformTransactionManager.rollback(transaction);
            throw new RuntimeException("库存不足");
       }
        // 4、更新库存操作
        int count = product.getCount() - purchaseNum;
        product.setCount(count);
        productMapper.updateById(product);
        // 5、创建订单
        TOrder order = new TOrder();
        order.setOrderStatus(1);//订单状态
        order.setReceiverName("张三");
        order.setReceiverMobile("18587781058");
      order.setOrderAmount(product.getPrice().multiply(new BigDecimal(purchaseNum)));//订单价格
        baseMapper.insert(order);
        // 6、创建订单和商品关联
        OrderItem orderItem = new OrderItem();
        orderItem.setOrderId(order.getId());//订单id
        orderItem.setProduceId(product.getId());// 商品id
        orderItem.setPurchasePrice(product.getPrice());// 购买价格
        orderItem.setPurchaseNum(purchaseNum);// 购买数量
        orderItemMapper.insert(orderItem);
        //提交事务
        platformTransactionManager.commit(transaction);
        return order.getId();
   }

分布式锁解决方案

 分布式的CAP理论告诉我们“任何一个分布式系统都无法同时满足一 致性(Consistency)、可用性(Availability)和分区容错性 (Partition tolerance),最多只能同时满足两项。”所以,很多系 统在设计之初就要对这三者做出取舍。在互联网领域的绝大多数的 场景中,都需要牺牲强一致性来换取系统的高可用性,系统往往只 需要保证“最终一致性”,只要这个最终时间是在用户可以接受的范围内即可。

 分布式锁实现方案

基于数据库实现的分布式锁

 基于数据库实现分布式锁主要是利用数据库的唯一索引来实现,唯 一索引天然具有排他性,这刚好符合我们对锁的要求:同一时刻只能允许一个竞争者获取锁。

 基于 Redis 实现的分布式锁

 使用Redis来实现分布式锁的效率最高,加锁速度最快,因为Redis 几乎都是纯内存操作,而基于数据库的方案和基于Zookeeper的方 案都会涉及到磁盘文件IO,效率相对低下。一般使用Redis来实现分 布式锁都是利用Redis的 SETNX key value 这个命令,只有当key不存在时 才会执行成功,如果key已经存在则命令执行失败。

基于 Zookeeper 实现的分布式锁 

 Zookeeper一般用作配置中心,其实现分布式锁的原理和Redis类 似,我们在Zookeeper中创建临时顺序节点,利用节点不能重复创建的特性来保证排他性。

 分布式锁解决方案_数据库悲观锁实现的分布式锁

 什么是悲观锁

顾名思义,就是比较悲观的锁,总是假设最坏的情况,每次去拿数 据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁, 这样别人想拿这个数据就会阻塞直到它拿到锁。

演示for update

开启2个命令行界面

 测试for update

 项目中使用for update

配置文件添加配置

mybatis-plus:
 mapper-locations: classpath:mapper/*.xml

mapper添加方法

public interface ProductMapper extends BaseMapper<Product> {
    Product  findById(@Param("id")Integer id);
}

mapper编写语句

<select id="findById" parameterType="int" resultType="com.tong.lock.entity.Product">
       select * from product where id = #{id} for update
</select>

修改订单接口实现类

@Transactional(rollbackFor = Exception.class)
    @Override
    public  String createOrder(Integer productId, Integer count) {
        // 1、根据商品id查询商品信息
        Product product = productMapper.findById(productId);
        // 2、判断商品是否存在
        if (product == null) {
            throw new RuntimeException("购买商品不存在:" + productId + "不存在");
       }
        // 3、校验库存
        if (count > product.getCount()) {
            throw new RuntimeException("商品" +productId + "仅剩" + product.getCount() + "件,无法购买");
       }
        // 4、计算库存
        Integer leftCount = product.getCount() - count;
        // 5、更新库存
        product.setCount(leftCount);
        productMapper.updateById(product);
        // 6、 创建订单
        TOrder order = new TOrder();
        order.setOrderStatus(1);//待处理
        order.setReceiverName("张三");
        order.setReceiverMobile("18587781068");
        order.setOrderAmount(product.getPrice().multiply(new BigDecimal(count)));//订单价格
        baseMapper.insert(order);
        // 7、 创建订单和商品关系数据
        OrderItem orderItem = new OrderItem();
        orderItem.setOrderId(order.getId());
        orderItem.setProduceId(product.getId());
        orderItem.setPurchasePrice(product.getPrice());
        orderItem.setPurchaseNum(count);
        orderItemMapper.insert(orderItem);
        return order.getId();
   }

压测吞吐量

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

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

相关文章

火山引擎云搜索服务升级云原生新架构;提供数十亿级分布式向量数据库能力

从互联网发展伊始&#xff0c;搜索技术就绽放出了惊人的社会和经济价值。随着信息社会快速发展&#xff0c;数据呈爆炸式增长&#xff0c;搜索技术通过数据收集与处理&#xff0c;满足信息共享与快速检索的需求。 云搜索服务 ESCloud 是火山引擎提供的完全托管在线分布式搜索服…

OJ练习第135题——下降路径最小和

下降路径最小和 力扣链接&#xff1a;931. 下降路径最小和 题目描述 给你一个 n x n 的 方形 整数数组 matrix &#xff0c;请你找出并返回通过 matrix 的下降路径 的 最小和 。 下降路径 可以从第一行中的任何元素开始&#xff0c;并从每一行中选择一个元素。在下一行选择…

永磁同步电机磁场定向控制(FOC)及Matlab/Simulink仿真分析

前言 做永磁同步电机控制绕不开FOC&#xff0c;本章节主要介绍FOC控制的基本原理、坐标变换以及永磁同步电机在同步旋转坐标系下的数学模型&#xff0c;并通过Matlab/Simulink进行永磁同步电机FOC控制算法的仿真分析。 01 FOC的基本原理 磁场定向控制&#xff08;Field-Ori…

分割3-转置卷积可逆吗?

上一话 分割2——语义分割评价指标https://blog.csdn.net/XiaoyYidiaodiao/article/details/125149509?spm1001.2014.3001.5502 转置卷积不是卷积的逆操作&#xff0c;并且转置卷积是卷积操作&#xff01; 这是因为普通卷积的操作图 1. 图1 其卷积可等效为图 2. 图2 其卷积操…

Offset Explorer2 监视kafka的利器

kafka作为一个生产者和消费者集为一体的框架&#xff0c;消费者必须一直保持打开的状态&#xff0c;并且每隔一段时间接收一次数据&#xff0c;才能够保持生产者放入的数据及时被处理掉&#xff0c;而生产者则可以每隔一段时间发送一波数据&#xff0c;这样消费者就能够接收到了…

Mysql搭建互为主从数据库

Mysql搭建互为主从数据库 一、搭建前期说明二、mysql文件结构以及配置说明1、mysqlA文件结构2、mysqlB文件结构3、mysqlA的配置文件my.cnf4、mysqlB的配置文件my.cnf5、启动mysqlA服务器脚本startMysqlA.sh6、启动mysqlB服务器脚本startMysqlB.sh7、查看服务启动情况 三、设置主…

【Redis】之缓存一致性

1、缓存一致性 对于使用 Redis 作为缓存来说&#xff0c;如何保证数据库和缓存数据一致性是个麻烦的问题。对于缓存和数据库的操作&#xff0c;主要有以下两种方式&#xff1a; 先删缓存&#xff0c;再更新数据库&#xff1b;先更新数据库&#xff0c;再删除缓存&#xff1b;…

【UE4 塔防游戏系列】02-基础设置

步骤 1. 新建一个蓝图&#xff0c;父类为游戏模式基础 命名为“TaFangGameMode” 2. 新建一个玩家控制器 命名为“TaFangGamePlayerController” 3. 在世界场景设置中&#xff0c;选择游戏覆盖模式为“TaFangGameMode” 默认Pawn类设为None&#xff0c;玩家控制器类选择“TaFa…

使用rest-assured框架优雅实现接口测试断言

对于接口测试来说&#xff0c;只判断响应状态码为200是远远不够的&#xff0c;我们经常必须去验证响应内容中的业务字段是否正确&#xff0c;本文将采用Rest-Assured框架来实现接口响应的判断。 1、接口信息的调试 当我们在做接口测试时&#xff0c;通常希望将接口的请求及响…

包装类(wrapper)

包装类(wrapper) 包装类和基本数据类型间的转换(Interger演示) public class WrapperType01 {public static void main(String[] args) {int a 10;// 手动封箱&#xff0c;Integer integer Integer.valueOf(a);System.out.println(integer);// 手动拆箱int i integer.intVa…

十五周算法训练营——岛屿问题

今天是十五周算法训练营的第十五周&#xff0c;主要讲岛屿问题专题。&#xff08;欢迎加入十五周算法训练营&#xff0c;与小伙伴一起卷算法&#xff09; 岛屿问题 一、题目 给你一个由 1&#xff08;陆地&#xff09;和 0&#xff08;水&#xff09;组成的的二维网格&#xff…

11. 利用Tomcat服务器配置HTTPS双向认定

文章目录 Tomcat配置HTTPS1.为服务器生成证书2.为客户端生成证书3.让服务器信任客户端证书4.将该文件导入到服务器的证书库&#xff0c;添加为一个信任证书使用命令如下&#xff1a;5.查看证书库6.让客户端信任服务器证书7.配置tomcat8.验证 Tomcat配置HTTPS 1.启动cmd控制台&…

分布式锁【分布式锁概述、业务介绍、创建SpringBoot项目】(一)-全面详解(学习总结---从入门到深化)

目录 分布式锁概述 分布式锁问题_业务介绍 分布式锁问题_创建SpringBoot项目 分布式锁概述 为什么需要分布式锁 在单机部署的系统中&#xff0c;使用线程锁来解决高并发的问题&#xff0c;多线程访问共享变量的问题达到数据一致性&#xff0c;如使用synchornized、 Reentran…

第一堂棒球课品牌设计·棒球1号位

需求背景 第一堂棒球课作为国内的创新体育课程&#xff0c;旨在为广大青少年提供一个更好的平台来接触并了解棒球这项运动。品牌的建设将影响到其在国内的认可度和知名度。在此背景下&#xff0c;我们的产品目标是为第一堂棒球课打造一个具有竞争力的品牌形象&#xff0c;满足…

基于jeecg-boot的nbcio-boot亿事达企业管理平台发布

目前这个演示系统与代码都同步&#xff0c;以后也尽量保持同步。 更多功能看演示系统 gitee源代码地址 后端代码&#xff1a; https://gitee.com/nbacheng/nbcio-boot 前端代码&#xff1a;https://gitee.com/nbacheng/nbcio-vue.git 在线演示&#xff08;包括H5&#xff…

「Java核心技术大会 2023」6月启动,邀你共同探讨Java生态

&#x1f935;‍♂️ 个人主页&#xff1a;艾派森的个人主页 ✍&#x1f3fb;作者简介&#xff1a;Python学习者 &#x1f40b; 希望大家多多支持&#xff0c;我们一起进步&#xff01;&#x1f604; 如果文章对你有帮助的话&#xff0c; 欢迎评论 &#x1f4ac;点赞&#x1f4…

数据结构 | 图的最短路径 Floyd算法

一、数据结构定义 typedef int VertexType; typedef int EdgeType;/*图*/ typedef struct {VertexType Vexs[SIZE]; //结点 EdgeType Edges[SIZE][SIZE]; //权值 int vexnum, arcnum; }MGraph;/*路径*/ typedef struct {int path[SIZE][SIZE];EdgeType length; }Path; 1.二维…

给父组件添加点击事件,点击时获取父组件的target

我想获取class为 mes-it 的dom元素结果每次拿到的 target都是子元素 查了查资料可以用 pointer-events: none; 来规避子元素成为target 就是上面图片style 里面的样式

【图灵奖得主Frederick P.Brooks, Jr.带你走进软件工程的世界——《人月神话》】

畅销业界48年的传奇经典 被引频次最高的软工神话 本书为复杂项目管理提供了极具洞察力的见解、发人深省的观点以及大量的软件工程实践。 直至今天&#xff0c;《人月神话》依然活跃在软件开发各个领域的话题中&#xff01; 我是一个书狂&#xff0c;积习甚深&#xff0c;费尽心…

Python自动化测试五大框架(测试员收藏夹必备)

自2018年被评选为编程语言以来&#xff0c;Python在各大排行榜上一直都是名列前茅。目前&#xff0c;它在Tiobe指数中排名第三个&#xff0c;仅次于Java和C。随着该编程语言的广泛使用&#xff0c;基于Python的自动化测试框架也应运而生&#xff0c;且不断发展与丰富。 因此&am…