Redis---------分布式锁Redisson

 概述

 Redisson入门

 第一步:引入依赖

        <dependency><groupId>org.redisson</groupId><artifactId>redisson</artifactId><version>3.13.6</version></dependency>

第二步:配置文件

import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class RedissonConfig {@Beanpublic RedissonClient redissonClient(){//配置Config config = new Config();config.useSingleServer().setAddress("redis://192.168.136.132:6379").setPassword("pz030812...");//创建RedissonClient对象return Redisson.create(config);}
}

第三步:使用锁

        Long id = UserHolder.getUser().getId();//创建锁对象RLock lock = redissonClient.getLock("lock:order" + id);//获取锁boolean trylock = lock.tryLock();//判断是否获得锁成功if (!trylock) {//获取锁失败return Result.fail("不允许重复下单!");}try {//获得锁进行操作//获得Spring的代理对象(事务)IVoucherOrderService proxy = (IVoucherOrderService) AopContext.currentProxy();return proxy.createVoucherOrder(voucherId);} finally {//释放锁lock.unlock();}

Redisson锁可重入原理

 就是在Lock中利用hash数据加一个标识字段,标识有几个自己线程中获得锁的数量,每次获取锁的流程:①判断锁是否存在,如果不存在则说明没人用锁,则获取到锁,并且设置好标识以及线程名②如果存在则判断是不是自己线程中的锁③如果不是,就说明是别人的锁,则获取失败返回错误④如果判断是自己线程的锁,则把标识字段+1,并且获得锁⑤之后只要是自己线程中的人来获取锁就直接更改标识。

而释放锁的流程:①先判断这个锁是不是自己线程的②如果不是就说明锁已经被释放了③如果是的话,就把标识减1④再去看标识是否已经等于0,即到了最外层⑤如果是的话就直接释放锁⑥不是的话就重置锁的有限期,继续执行业务

 Redisson锁可重试,超时释放(看门狗)原理

 Redisson锁主从一致性

multiLock原理:

异步实现秒杀商品

 执行流程:将判断资格和写进数据库分离开来,使得并发能力大大增强

 

 代码执行:

①在添加秒杀商品的同时,将数据写进Redis当中

 @Transactionalpublic void addSeckillVoucher(Voucher voucher) {// 保存优惠券save(voucher);// 保存秒杀信息SeckillVoucher seckillVoucher = new SeckillVoucher();seckillVoucher.setVoucherId(voucher.getId());seckillVoucher.setStock(voucher.getStock());seckillVoucher.setBeginTime(voucher.getBeginTime());seckillVoucher.setEndTime(voucher.getEndTime());seckillVoucherService.save(seckillVoucher);//保存秒杀劵到Redis中stringRedisTemplate.opsForValue().set("seckill:stock"+voucher.getId(),voucher.getStock().toString());}

 ②编写Lua脚本,实现资格判断

--1.参数列表
--1.1。优惠券id
local voucherId = ARGV[1]
--1.2.用户id
local userId = ARGV[2]--2.数据key
--2.1 库存key
local stockKey = 'seckill:stock' .. voucherId
--2.1 订单id
local orderKey = 'seckill:order' .. voucherId--3.脚本业务
--3.1,判断库存是否充足 get stockKey
if(tonumber(redis.call('get',stockKey)) <= 0) thenreturn 1end
--3.2 判断用户是否下单 SISMEMBER orderKey userID
if(redis.call('sismember',orderKey,userId) == 1) then--3.3 存在,说明是重复下单,返回2return 2
end
--3.4 扣库存
redis.call('incrby',stockKey,-1)
--3.5 下单
redis.call('sadd',orderKey,userId)

③编码

@Service
public class VoucherOrderServiceImpl extends ServiceImpl<VoucherOrderMapper, VoucherOrder> implements IVoucherOrderService {@Autowiredprivate ISeckillVoucherService iSeckillVoucherService;@Autowiredprivate RedisUUID redisUUID;@Autowiredprivate StringRedisTemplate stringRedisTemplate;@Autowiredprivate RedissonClient redissonClient;private static final DefaultRedisScript<Long> SECKILL_SCRIPT;static {SECKILL_SCRIPT = new DefaultRedisScript<>();SECKILL_SCRIPT.setLocation(new ClassPathResource("seckill.lua"));SECKILL_SCRIPT.setResultType(Long.class);}//创建阻塞队列private BlockingDeque<VoucherOrder> orderTasks = new ArrayBlockingQueue<>(1024 * 1024);//创建线程池private static final ExecutorService SECKILL_ORDER_EXECUTOR = Executors.newSingleThreadExecutor();@PostConstructprivate void init(){SECKILL_ORDER_EXECUTOR.submit(new VoucherOrderHandler());}private class VoucherOrderHandler implements Runnable{public void run(){while (true){try {//1,获取队列中的订单信息VoucherOrder voucherOrder = orderTasks.take();//2.创建订单handleVoucherOrder(voucherOrder);} catch (InterruptedException e) {log.error("处理订单异常!",e);}}}}private void handleVoucherOrder(VoucherOrder voucherOrder) {Long userId = voucherOrder.getUserId();//创建锁对象RLock lock = redissonClient.getLock("lock:order" + userId);//获取锁boolean trylock = lock.tryLock();//判断是否获得锁成功if (!trylock) {//获取锁失败return;}try {proxy.createVoucherOrder(voucherOrder);} finally {//释放锁lock.unlock();}}private IVoucherOrderService proxy;@Overridepublic Result seckillVoucher(Long voucherId) {Long id = UserHolder.getUser().getId();//1.执行Lua脚本Long result = stringRedisTemplate.execute(SECKILL_SCRIPT,Collections.emptyList(),voucherId.toString(),id.toString());//2.判断结果为0int r = result.intValue();if (r != 0){//2.1 不为0,代表没有购买资格return Result.fail(r == 1 ? "库存不足" : "不能重复下单");}//2.2 为0,有购买资格,把下单信息保存到阻塞队列VoucherOrder voucherOrder = new VoucherOrder();//2.3,订单id----id生成器long order = redisUUID.nextid("order");voucherOrder.setVoucherId(order);//2.4,用户idvoucherOrder.setUserId(id);//2.5,商品idvoucherOrder.setVoucherId(voucherId);//2.6,放入阻塞队列orderTasks.add(voucherOrder);//获取代理对象proxy = (IVoucherOrderService) AopContext.currentProxy();//3.返回订单idreturn Result.ok(order);}@Transactionalpublic void createVoucherOrder(VoucherOrder voucherOrder) {//一人一单问题Long id = voucherOrder.getUserId();Integer count = query().eq("user_id", id).eq("voucher_id", voucherOrder.getVoucherId()).count();if(count > 0){return;}//4,如果有就减扣库存boolean sucess = iSeckillVoucherService.update().setSql("stock = stock - 1").eq("voucher_id", voucherOrder.getVoucherId()).gt("stock",0).update();if (!sucess) {return;}//6,保存进数据库save(voucherOrder);}
}

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

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

相关文章

STM32——WWDG(窗口看门狗)

技术笔记&#xff01; 1.WWDG&#xff08;窗口看门狗&#xff09;简介 本质&#xff1a;能产生系统复位信号和提前唤醒中断的计数器。 特性&#xff1a; 递减的计数器&#xff1b; 当递减计数器值从 0x40减到0x3F时复位&#xff08;即T6位跳变到0&#xff09;&#xff1b; …

Netty 网络编程深入学习【一】:ByteBuffer 源码解析

ByteBuffer源码阅读 ByteBuffer是一个用于处理字节数据的缓冲区类。它是Java NIO 包的一部分&#xff0c;提供了一种高效的方式来处理原始字节数据。 ByteBuffer 可以用来读取、写入、修改和操作字节数据&#xff0c;它是一种直接操作字节的方式&#xff0c;比起传统的 InputSt…

使用OpenCV绘制两幅图验证DSC和IoU以及BCELoss的计算程序

1.创作灵感 很多小伙伴在玩深度学习模型的时候,需要计算Groudtruth和predict图的dsc、IOU以及BCELoss。这两个关键的指标的程序有很多种写法,今天使用OpenCV绘制两张已知分布的图像,计算其dsc、IOU以及BCELoss。 2、图像如图所示 在一个100100的区域内,红色框范围为预测…

我的毕业实习经历

我的毕业实习经历 前言求职之路成为社畜重获自由结语 前言 这篇博客原本我想以实习生找工作踩坑指南&#xff1a;我的毕业实习经历为文章标题的&#xff0c;原因是跟我前面发布的一篇博客《实习生找工作踩坑指南&#xff1a;租房篇》做一个呼应收尾&#xff0c;奈何标题略显臃肿…

c3 笔记8 css排版技巧

相关内容&#xff1a;边界、边框、位置&#xff08;absolute、relative、static&#xff09;、overflow、z-index、超链接、鼠标光标特效、…… margin:上边界值 右边界值 下边界值 左边界值 笔记来源&#xff1a; ©《HTML5CSS3JavaScript网页设计》陈婉凌编&#xff…

固定资产管理系统

固定资产管理系统 摘 要 随着计算机信息技术的发展以及对资产、设备的管理科学化、合理化的高要求&#xff0c;利用计算机实现设备及资产的信息化管理已经显得非常重要。 固定资产管理系统是一个单位不可缺少的部分。但一直以来人们使用传统的人工方式管理固定资产的信息&…

【大数据】学习笔记

文章目录 [toc]NAT配置IP配置SecureCRT配置PropertiesTerminal Java安装环境变量配置 Hadoop安装修改配置文件hadoop-env.shyarn-env.shslavescore-site.xmlhdfs-site.xmlmapred-site.xmlyarn-site.xml 环境变量配置 IP与主机名映射关系配置hostname配置映射关系配置 关闭防火墙…

[每日AI·0501]GitHub 版 Devin,Transformer的强力挑战者 Mamba,Sora 制作细节与踩坑,OpenAI 记忆功能

AI 资讯 国资委&#xff1a;加快人工智能等新技术与制造全过程、全要素深度融合GitHub版 Devin 上线&#xff0c;会打字就能开发应用&#xff0c;微软 CEO&#xff1a;重新定义 IDE在12个视频理解任务中&#xff0c;Mamba 先打败了 TransformerSora 会颠覆电影制作吗&#xff…

Linux POSIX消息队列遇到的问题和使用方法

目录 一、开发环境及消息队列介绍二、问题描述三、解决办法四、测试代码 一、开发环境及消息队列介绍 开发板&#xff1a;nuc980 1.ARM Linux中消息队列的原理   在ARM Linux中&#xff0c;消息队列是通过POSIX&#xff08;Portable Operating System Interface&#xff09…

idea 新建spring maven项目、ioc和依赖注入

文章目录 一、新建Spring-Maven项目二、在Spring-context使用IOC和依赖注入 一、新建Spring-Maven项目 在pom.xml文件中添加插件管理依赖 <build><plugins><plugin><artifactId>maven-compiler-plugin</artifactId><version>3.1</ver…

来一篇错题集(虽然简单吧)

一.Assembly via Remainders #include<bits/stdc.h> using namespace std; typedef long long ll; int a[2000]; int b[2000]; int main(){int t;cin>>t;while(t--){int n;cin>>n;for(int i1;i<n-1;i){cin>>b[i];}int x1000000000;//使用1000000000…

算法打卡day40

今日任务&#xff1a; 1&#xff09;139.单词拆分 2&#xff09;多重背包理论基础&#xff08;卡码网56携带矿石资源&#xff09; 3&#xff09;背包问题总结 4&#xff09;复习day15 139单词拆分 题目链接&#xff1a;139. 单词拆分 - 力扣&#xff08;LeetCode&#xff09; …

LLaVA:分析图像和文本数据的开源模型

原文地址&#xff1a;analyzing-images-with-llava 2024 年 3 月 20 日 在过去的几个月里&#xff0c;ChatGPT 等各种大型语言模型&#xff08;LLM&#xff09;已进入商业市场&#xff0c;许多公司已成功地将 LLM 集成到其产品和服务中&#xff0c;极大地改变了我们与设备和互…

RocketMQ SpringBoot 3.0不兼容解决方案

很多小伙伴在项目升级到springBoot3.0版本以上之后&#xff0c;整合很多中间件会有很多问题&#xff0c;下面带小伙伴解决springBoot3.0版本以上对于RocketMQ 不兼容问题 报错信息 *************************** APPLICATION FAILED TO START *************************** Des…

【JVM】JMM 内存模型

JMM 概述 内存模型 java[内存模型](Java Memory Model) 和 [内存结构]JMM规定了在多线程下对共享数据的读写时&#xff0c;对数据的原子性 有序性 可见性的规则和保障。 原子性 原子性问题: i和i–不是原子性操作! 所以一个i指令会在执行过程中被另一个线程执行! 问题分…

C++ | Leetcode C++题解之第67题二进制求和

题目&#xff1a; 题解&#xff1a; class Solution { public:string addBinary(string a, string b) {string ans;reverse(a.begin(), a.end());reverse(b.begin(), b.end());int n max(a.size(), b.size()), carry 0;for (size_t i 0; i < n; i) {carry i < a.siz…

最佳实践|Apifox 中通过 CryptoJS 给请求参数进行 AES 加密!

假如现在要在 Apifox 中发送一个「登录」的请求&#xff0c;然后我需要将接口中的 password 参数使用 AES 加密算法加密以后&#xff0c;再传给后台服务&#xff0c;这要怎么做&#xff1f; 要在 Apifox 中使用 AES 加密算法对 password 参数进行加密&#xff0c;你需要在「前置…

4 Spring AOP

目录 AOP 简介 传统开发模式 先来看一个需求 解决方案 AOP 图示 Spring 启用 AspectJ 基于 xml 配置 创建 pom.xml 创建 UserService 借口和 UserServiceImpl实现类 创建 LogAdvice 日志通知 创建 log4j.properties 重点&#xff1a;创建 spring-context-xml.xml 配…

如何让 PDF 书签从杂乱无序整洁到明丽清新

1、拉取书签&#xff08;详细步骤看文末扩展阅读&#xff09; 原状态 —— 杂乱无序 自动整理后的状态 —— 错落有致&#xff0c;但摩肩接踵 2、开始整理 全选自动整理后的书签&#xff0c;剪切 访问中英混排排版优化 - 油条工具箱 https://utils.fun/cn-en 1 粘贴 → 2 …

国科大模版修订模式冲突

定位到 \documentclass[twoside]{Style/ucasthesis}%前添加\PassOptionsToPackage{changes,usenames,dvipsnames,table}{xcolor} 完整如下&#xff1a; \PassOptionsToPackage{changes,usenames,dvipsnames,table}{xcolor} \documentclass[twoside]{Style/ucasthesis}% \us…