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

2024-05-04 11:44
文章标签 redis 分布式 redisson

本文主要是介绍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);}
}

这篇关于Redis---------分布式锁Redisson的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/959120

相关文章

Redis MCP 安装与配置指南

《RedisMCP安装与配置指南》本文将详细介绍如何安装和配置RedisMCP,包括快速启动、源码安装、Docker安装、以及相关的配置参数和环境变量设置,感兴趣的朋友一起看看吧... 目录一、Redis MCP 简介二、安www.chinasem.cn装 Redis MCP 服务2.1 快速启动(推荐)2.

Redis中Stream详解及应用小结

《Redis中Stream详解及应用小结》RedisStreams是Redis5.0引入的新功能,提供了一种类似于传统消息队列的机制,但具有更高的灵活性和可扩展性,本文给大家介绍Redis中Strea... 目录1. Redis Stream 概述2. Redis Stream 的基本操作2.1. XADD

Jenkins分布式集群配置方式

《Jenkins分布式集群配置方式》:本文主要介绍Jenkins分布式集群配置方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1.安装jenkins2.配置集群总结Jenkins是一个开源项目,它提供了一个容易使用的持续集成系统,并且提供了大量的plugin满

Knife4j+Axios+Redis前后端分离架构下的 API 管理与会话方案(最新推荐)

《Knife4j+Axios+Redis前后端分离架构下的API管理与会话方案(最新推荐)》本文主要介绍了Swagger与Knife4j的配置要点、前后端对接方法以及分布式Session实现原理,... 目录一、Swagger 与 Knife4j 的深度理解及配置要点Knife4j 配置关键要点1.Spri

Redis出现中文乱码的问题及解决

《Redis出现中文乱码的问题及解决》:本文主要介绍Redis出现中文乱码的问题及解决,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1. 问题的产生2China编程. 问题的解决redihttp://www.chinasem.cns数据进制问题的解决中文乱码问题解决总结

Redis的持久化之RDB和AOF机制详解

《Redis的持久化之RDB和AOF机制详解》:本文主要介绍Redis的持久化之RDB和AOF机制,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录概述RDB(Redis Database)核心原理触发方式手动触发自动触发AOF(Append-Only File)核

Redis分片集群、数据读写规则问题小结

《Redis分片集群、数据读写规则问题小结》本文介绍了Redis分片集群的原理,通过数据分片和哈希槽机制解决单机内存限制与写瓶颈问题,实现分布式存储和高并发处理,但存在通信开销大、维护复杂及对事务支持... 目录一、分片集群解android决的问题二、分片集群图解 分片集群特征如何解决的上述问题?(与哨兵模

SpringBoot连接Redis集群教程

《SpringBoot连接Redis集群教程》:本文主要介绍SpringBoot连接Redis集群教程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1. 依赖2. 修改配置文件3. 创建RedisClusterConfig4. 测试总结1. 依赖 <de

SpringBoot+Redis防止接口重复提交问题

《SpringBoot+Redis防止接口重复提交问题》:本文主要介绍SpringBoot+Redis防止接口重复提交问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不... 目录前言实现思路代码示例测试总结前言在项目的使用使用过程中,经常会出现某些操作在短时间内频繁提交。例

Redis 配置文件使用建议redis.conf 从入门到实战

《Redis配置文件使用建议redis.conf从入门到实战》Redis配置方式包括配置文件、命令行参数、运行时CONFIG命令,支持动态修改参数及持久化,常用项涉及端口、绑定、内存策略等,版本8... 目录一、Redis.conf 是什么?二、命令行方式传参(适用于测试)三、运行时动态修改配置(不重启服务