基于 Redis 实现的分布式锁

获取锁

互斥:确保只有一个线程获得锁

# 添加锁 利用setnx的互斥性
127.0.0.1:6379> setnx lock thread1

释放锁

手动释放锁
超时释放:获取锁时设置一个超时时间

#释放锁 删除即可
127.0.0.1:6379> del lock

两步合成一步

 help set


  SET key value [EX seconds] [PX milliseconds] [NX|XX]
  summary: Set the string value of a key
  since: 1.0.0
  group: string


127.0.0.1:6379> get k1
(nil)
127.0.0.1:6379> set lock k1 ex 5 nx
OK
127.0.0.1:6379> set lock k1 ex 5 nx
nil

在这里插入图片描述
在这里插入图片描述

分布式锁解决方案_Redis实现的分布式锁

编写创建订单实现类

 @Override
  public String createOrderRedis(Integer productId, Integer count) throws Exception {


    log.info("*************** 进入方法 **********");
    String key = "lock:";
    String value = UUID.randomUUID().toString();


    // 获取分布式锁
    Boolean result = stringRedisTemplate.opsForValue().setIfAbsent(key+productId, String.valueOf(Thread.currentThread().getId()),30,TimeUnit.SECONDS);
    // 判断是否获取锁成功
    if (!result){
      log.info("我进入了锁");
      return "不允许重复下单";
     }
    try {
      // 1、根据商品id查询商品信息
      Product product = productMapper.selectById(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();
     }catch (Exception e){
      e.printStackTrace();
     }finally {
      // 释放锁
      stringRedisTemplate.delete(key+productId);
     }
    return "创建失败";
   }

Redis分布式锁误删除问题

Redis分布式锁误删除问题解决方案
设置超时时间远大于业务执行时间,但是会带来性能问题
删除锁的时候要判断,是不是自己的,如果是再删除

配置锁标识

private static final String KEY_PREFIX = "lock:";
  private static final String ID_PREFIX = UUID.randomUUID().toString().replace("-","");

获取锁



    //1、获取线程标识
    String threadId = ID_PREFIX + Thread.currentThread().getId();
 // 2、获得锁  setnx  key  value  time  type
    Boolean result = stringRedisTemplate.opsForValue().setIfAbsent(KEY_PREFIX+produceId, threadId, 30, TimeUnit.SECONDS);

释放锁

// 获取锁标识
      String s = stringRedisTemplate.opsForValue().get(KEY_PREFIX + produceId);
      // 判断标识是否一致
      if (s.equals(threadId)){
        // 释放锁
        stringRedisTemplate.delete(KEY_PREFIX + produceId);
       }

Redis分布式锁不可重入问题

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

分布式锁解决方案_基于Redisson实现的分布式锁实现

Redisson介绍
Redisson - 是一个高级的分布式协调Redis客服端,能帮助用户在分布式环境中轻松实现一些Java的对象,Redisson、Jedis、Lettuce 是三个不同的操作 Redis 的客户端,Jedis、Lettuce 的 API 更侧重对 Reids 数据库的 CRUD(增删改查),而 Redisson API 侧重于分布式开发。

<dependency>
      <groupId>org.redisson</groupId>
      <artifactId>redisson-spring-boot-starter</artifactId>
      <version>3.17.2</version>
 </dependency>

编写Redis分布式锁工具类

package com.itbaizhan.lock.utils;


import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;


import java.util.concurrent.TimeUnit;


@Component
@Slf4j
public class DistributedRedisLock {


  @Autowired
  private RedissonClient redissonClient;


  // 加锁
  public Boolean lock(String lockName) {
    if (redissonClient == null) {
      log.info("DistributedRedisLock redissonClient is null");
      return false;
     }


    try {
      RLock lock = redissonClient.getLock(lockName);
      // 锁15秒后自动释放,防止死锁
      lock.lock(15, TimeUnit.SECONDS);


      log.info("Thread [{}] DistributedRedisLock lock [{}] success", Thread.currentThread().getName(), lockName);
      // 加锁成功
      return true;
     } catch (Exception e) {
      log.error("DistributedRedisLock lock [{}] Exception:", lockName, e);
      return false;
     }
   }


  // 释放锁
  public Boolean unlock(String lockName) {
    if (redissonClient == null) {
      log.info("DistributedRedisLock redissonClient is null");
      return false;
     }


    try {
      RLock lock = redissonClient.getLock(lockName);
      lock.unlock();
      log.info("Thread [{}] DistributedRedisLock unlock [{}] success", Thread.currentThread().getName(), lockName);
      // 释放锁成功
      return true;
     } catch (Exception e) {
      log.error("DistributedRedisLock unlock [{}] Exception:", lockName, e);
      return false;
     }
   }
}



编写创建订单接口实现

 /**
   * Redis锁实现
   *
   * @param productId
   * @param count
   * @return
   * @throws Exception
   */
  @Override
  public String createOrderRedis(Integer productId, Integer count) throws Exception {
    //获取锁对象
    if (distributedRedisLock.lock(String.valueOf(productId))) {
      try {
        // 1、根据商品id查询商品信息
        Product product = productMapper.selectById(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();
       } catch (Exception e) {
        e.printStackTrace();
       } finally {
        distributedRedisLock.unlock(String.valueOf(productId));
       }
     }
    return "创建失败";
   }

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

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

相关文章

(六)七种元启发算法(DBO、LO、SWO、COA、LSO、KOA、GRO)求解无人机路径规划MATLAB

一、七种算法&#xff08;DBO、LO、SWO、COA、LSO、KOA、GRO&#xff09;简介 1、蜣螂优化算法DBO 蜣螂优化算法&#xff08;Dung beetle optimizer&#xff0c;DBO&#xff09;由Jiankai Xue和Bo Shen于2022年提出&#xff0c;该算法主要受蜣螂的滚球、跳舞、觅食、偷窃和繁…

达索系统SOLIDWORKS 2024钣金和结构系统新功能

达索系统SOLIDWORKS钣金和结构系统是大家比较熟悉的模块了&#xff0c;在2024版本中钣金和结构系统功能也做了很棒的提升。接下来让我们看看如何使用达索系统SOLIDWORKS 2024钣金和结构系统的一些新功能快速完成相应的设计。 达索系统SOLIDWORKS 2024的钣金提供了槽口延伸功能…

JavaWeb——CSS3的使用

目录 1. CSS概述 2. CSS引入方式 3. CSS颜色显示 4. CSS选择器 4.1. 元素&#xff08;标签&#xff09;选择器 4.2. id选择器 4.3. 类选择器 4.4. 三者优先级 5. 盒子模型 1. CSS概述 CSS&#xff0c;全称为“Cascading Style Sheets”&#xff0c;中文译为“层叠样式…

CM211-1 MC022主板输入刷Armbian

咋一看以为是NAND的存储&#xff0c;经过各方搜索&#xff0c;发现BWCMMQ511G08G存储芯片是狭义的NAND&#xff0c;支持emmc协议&#xff0c;故而做尝试。 烧写步骤 1.下载Armbian镜像 Armbian_23.11.0_amlogic_s905l3-cm211_lunar_6.1.60_server_2023.11.01.img.gz 2.将镜像…

影响因子10月修正!多本期刊上涨,最高IF达54.8!

【SciencePub学术】 每年的影响因子基本都在6月底发布&#xff0c;但是由于数据不全等原因&#xff0c;部分期刊未能及时获得影响因子&#xff0c;或者影响因子有一定误差。因此&#xff0c;每年科睿唯安还会在10或11月份对当年的影响因子进行更新&#xff0c;主要包括补录和修…

在CentOS7环境下安装Mysql

1.卸载已有的不需要的环境 使用如下命令&#xff0c;查看系统中是否已经存在mysql和mariadb&#xff08;mysql的一个子分支&#xff09; ps ajx | grep mariadb ps ajx | grep mysql 如果显示与我相同&#xff0c;则代表系统中已经存在这些环境并且已经停止 如果不相同则需要…

github使用手册

核心代码 配置用户名/邮箱 best practice git init #在本地初始化一个仓库 git add . #将当前目录所有的文件加入&#xff08;注意这里是加入&#xff09;到缓存区 git commit -m "xxx" #将当前缓存区里的内容提交到本地仓库 git remote add <remote_rep_name&g…

java实现插入排序

图解 以下是Java实现插入排序的代码&#xff1a; public class InsertionSort {public static void main(String[] args) {int[] arr {5, 2, 4, 6, 1, 3};insertionSort(arr);System.out.println(Arrays.toString(arr)); // output: [1, 2, 3, 4, 5, 6]}public static void i…

Java实现身份证号校验,最后一位校验码校验

中国居民身份证号码编码规则 第一、二位表示省&#xff08;自治区、直辖市、特别行政区&#xff09;。 第三、四位表示市&#xff08;地级市、自治州、盟及国家直辖市所属市辖区和县的汇总码&#xff09;。其中&#xff0c;01-20&#xff0c;51-70表示省直辖市&#xff1b;21-5…

技术架构 - 应用数据分离,应用服务集群架构

前言 上一篇文章介绍了单机架构&#xff0c;由于性能瓶颈&#xff0c;满足不了高访问量&#xff0c;所以演化出了数据分离架构。 这种架构也很简单只是将应用服务和数据库服务分离开来&#xff0c;避免单一架构的资源争夺的情况。 一、 应用数据分离架构 1. 简介 应用服务和…

k8s资源管理操作——陈述式管理方式

目录 陈述式资源管理方式 1、常用的kubernetes管理命令 1&#xff09;查看版本信息 2&#xff09;查看资源对象简写 3&#xff09;查看集群信息 4&#xff09;配置kubectl自动补全 5&#xff09;node节点查看日志 2、资源管理命令 1&#xff09;创建资源 2&#xff0…

Java怎么对复杂的数据类型排序和比大小

目录 一.对复杂的数据类型比大小 Comparable接口 compareTo方法 二.对复杂数据类型排序 三.总结 一.对复杂的数据类型比大小 假如我们现在有个学生类&#xff0c;并且我们实例化出了俩个学生对象&#xff0c;他们各自有各自的名字和年龄属性&#xff0c;我们如何对他们进…

搜维尔科技:丰田汽车采用 Xsens 运动跟踪技术来监控员工的身体健康并维持安全

Movella Holdings Inc.通过其传感器、软件和分析的全栈产品实现运动数字化&#xff0c;提供可提高汽车制造工人安全的数据。丰田汽车欧洲公司正在其上半身和下半身人体工学分析工具中利用 Movella 的 MVN Analytics™ 数据来排除生产线流程和车辆设计的故障。 丰田汽车欧洲公司…

计算机视觉基础(7)——相机基础

前言 从这一节开始&#xff0c;我们来学习几何视觉。中层视觉包括相机模型、单目几何视觉、对极几何视觉和多目立体视觉等。在学习几何视觉最开始&#xff0c;我们先来学习一下相机模型&#xff0c;了解相机的基本原理&#xff0c;了解相机如何记录影像。 一、数字相机 1.1 基…

【milkv】2、mpu6050驱动添加及测试

前言 本章介绍mpu6050的驱动添加以及测试。 其中驱动没有采用sdk提供的驱动&#xff0c;一方面需要配置irq&#xff0c;另一方面可以学习下如何通过ko方式添加驱动。 一、参考文章 驱动及测试文件编译流程&#xff1a; https://community.milkv.io/t/risc-v-milk-v-lsm6ds…

YOLOV5中parser参数配置

源码下载链接&#xff1a;ultralytics/yolov5: YOLOv5 &#x1f680; in PyTorch > ONNX > CoreML > TFLite (github.com) 需要配置的参数&#xff1a;--data parser.add_argument(--data, ...)&#xff1a;添加一个用于数据配置文件的路径的参数。 可以直接修改&am…

VBA技术资料MF82:替换文件夹中文件名中的字符

我给VBA的定义&#xff1a;VBA是个人小型自动化处理的有效工具。利用好了&#xff0c;可以大大提高自己的工作效率&#xff0c;而且可以提高数据的准确度。我的教程一共九套&#xff0c;分为初级、中级、高级三大部分。是对VBA的系统讲解&#xff0c;从简单的入门&#xff0c;到…

『数据结构与算法』散列表(哈希表)

1. 什么是散列表 散列表&#xff08;Hash Table&#xff09;也叫哈希表&#xff0c;是根据给定关键字&#xff08;Key&#xff09;来计算出该关键字在表中存储地址的数据结构。也就是说&#xff0c;散列表建立了关键字与存储地址之间的一种直接映射关系&#xff0c;将关键字映…

[文件读取]shopxo 文件读取(CNVD-2021-15822)

1.1漏洞描述 漏洞编号CNVD-2021-15822漏洞类型文件读取漏洞等级⭐⭐漏洞环境VULFOCUS攻击方式 描述: ShopXO是一套开源的企业级开源电子商务系统。 ShopXO存在任意文件读取漏洞&#xff0c;攻击者可利用该漏洞获取敏感信息。 1.2漏洞等级 高危 1.3影响版本 ShopXO 1.4漏洞复现…

【C++】泛型编程 ① ( 函数模板 | 函数模板概念 | 函数模板意义 | 函数模板定义语法 | 函数模板调用语法 | 显式类型调用 | 自动类型推导 )

文章目录 一、函数模板简介1、函数模板概念2、函数模板意义 二、函数模板语法1、函数模板定义语法2、函数模板调用语法 三、函数模板代码示例1、代码示例2、执行结果 四、函数模板代码示例 - 声明多个泛型的情况1、代码示例2、执行结果 一、函数模板简介 1、函数模板概念 在 C …