基于 Redis 实现的分布式锁

获取锁

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

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

释放锁

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

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

两步合成一步

 help setSET key value [EX seconds] [PX milliseconds] [NX|XX]summary: Set the string value of a keysince: 1.0.0group: string127.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实现的分布式锁

编写创建订单实现类

 @Overridepublic 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  typeBoolean 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 {@Autowiredprivate 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*/@Overridepublic 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 "创建失败";}

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

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

相关文章

hive里因为列名用了关键字导致建表失败

代码 现象 ParseException line 6:4 cannot recognize input near percent String COMMENT in column name or primary key or foreign key 23/11/13 11:52:57 ERROR org.apache.hadoop.hive.ql.Driver: FAILED: ParseException line 6:4 cannot recognize input near percent …

Linux C 进程编程

进程编程 进程介绍进程的定义进程和线程以及程序的区别进程块PCB进程的状态相关指令 进程调度算法先来先服务调度算法 FCFS短作业(进程)优先调度算法 SJF优先权调度算法 FPF优先权调度算法的类型非抢占式优先权算法抢占式优先权算法 优先权类型静态优先权动态优先权 高响应比优…

MQ四大消费问题一锅端:消息不丢失 + 消息积压 + 重复消费 + 消费顺序性

RabbitMQ-如何保证消息不丢失 生产者把消息发送到 RabbitMQ Server 的过程中丢失 从生产者发送消息的角度来说&#xff0c;RabbitMQ 提供了一个 Confirm&#xff08;消息确认&#xff09;机制&#xff0c;生产者发送消息到 Server 端以后&#xff0c;如果消息处理成功&#xff…

MySQL 人脸向量,欧几里得距离相似查询

前言 如标题&#xff0c;就是通过提取的人脸特征向量&#xff0c;写一个欧几里得 SQL 语句&#xff0c;查询数据库里相似度排前 TOP_K 个的数据记录。做法虽然另类&#xff0c;业务层市面上有现成的面部检索 API&#xff0c;技术层现在有向量数据库。 用 MySQL 关系型存储 128 …

C语言 每日一题 牛客网 11.13 Day17

找零 Z国的货币系统包含面值1元、4元、16元、64元共计4种硬币&#xff0c;以及面值1024元的纸币。 现在小Y使用1024元的纸币购买了一件价值为N(0 < N≤1024)的商品&#xff0c;请问最少他会收到多少硬币&#xff1f; 思路 运用if语句进行判断分类 代码实现 int main() {…

执行力太差的人,如何才能提高执行力?

执行力是计划的落地执行&#xff0c;是按照计划稳步推进&#xff0c;导向结果的能力。不同的人&#xff0c;其执行力有很大的差别。比如说有拖延症的人&#xff0c;基本上是谈不上执行力的&#xff0c;执行力是一个综合体&#xff0c;是多个要素的共同作用。 在企业HR人才测评…

【左程云算法全讲10】打表技巧和矩阵处理技巧

系列综述&#xff1a; &#x1f49e;目的&#xff1a;本系列是个人整理为了秋招面试的&#xff0c;整理期间苛求每个知识点&#xff0c;平衡理解简易度与深入程度。 &#x1f970;来源&#xff1a;材料主要源于左程云算法课程进行的&#xff0c;每个知识点的修正和深入主要参考…

Java进阶(垃圾回收GC)——理论篇:JVM内存模型 垃圾回收定位清除算法 JVM中的垃圾回收器

前言 JVM作为Java进阶的知识&#xff0c;是需要Java程序员不断深度和理解的。 本篇博客介绍JVM的内存模型&#xff0c;对比了1.7和1.8的内存模型的变化&#xff1b;介绍了垃圾回收的语言发展&#xff1b;阐述了定位垃圾的方法&#xff0c;引用计数法和可达性分析发以及垃圾清…

使用阿里云服务器学习Docker

首先我这里选择的系统服务器是CentOS 7.9 64位 因为centos系统里面的安装指令是&#xff1a;yum,而非apt-get. yum install docker -y试着建立一个容器&#xff1a; docker run -d -p 80:80 httpd启动docker的守护进程&#xff1a; sudo systemctl start docker 查看Docke…

一张图搞懂什么是BCD8421编码

如图所示 BCD8421编码的意义是 用四位二进制数表达一位的十进制数 因此十进制下的0&#xff5e;9在BCD8421编码下与其二进制表达是一样的 而多位的十进制数 比如说“10” 则需要将它拆分成两个单独的数“1”和“0” 分别用BCD8421编码表示这两个数 十进制“1” -> 0001 十进…

快速掌握队列的基础知识

目录 队列的特点基于链表实现队列用栈实现队列用队列实现栈 队列是一种线性数据结构&#xff0c;它只允许在一边进行插入操作&#xff08;队尾&#xff09;&#xff0c;另一边进行删除操作&#xff08;队头&#xff09;。插入操作称为入队&#xff0c;删除操作称为出队。队列遵…

代理模式-静态动态代理-jdk动态代理-cglib动态代理

代理模式 静态代理 动态代理&#xff1a;jdk动态代理 cglib动态代理 注意 &#xff1a;下面的代码截图 要配合文字去看 我对代码的每一步都做了解释 所以需要配合图片观看提取吗1111https://pan.baidu.com/s/1OxQSwbQ--t5Zvmwzjh1T0A?pwd1111 这里直接把项目文件 及代码 …