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主从/哨兵机制原理分析

《Redis主从/哨兵机制原理分析》本文介绍了Redis的主从复制和哨兵机制,主从复制实现了数据的热备份和负载均衡,而哨兵机制可以监控Redis集群,实现自动故障转移,哨兵机制通过监控、下线、选举和故... 目录一、主从复制1.1 什么是主从复制1.2 主从复制的作用1.3 主从复制原理1.3.1 全量复制

Redis延迟队列的实现示例

《Redis延迟队列的实现示例》Redis延迟队列是一种使用Redis实现的消息队列,本文主要介绍了Redis延迟队列的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习... 目录一、什么是 Redis 延迟队列二、实现原理三、Java 代码示例四、注意事项五、使用 Redi

Redis缓存问题与缓存更新机制详解

《Redis缓存问题与缓存更新机制详解》本文主要介绍了缓存问题及其解决方案,包括缓存穿透、缓存击穿、缓存雪崩等问题的成因以及相应的预防和解决方法,同时,还详细探讨了缓存更新机制,包括不同情况下的缓存更... 目录一、缓存问题1.1 缓存穿透1.1.1 问题来源1.1.2 解决方案1.2 缓存击穿1.2.1

redis-cli命令行工具的使用小结

《redis-cli命令行工具的使用小结》redis-cli是Redis的命令行客户端,支持多种参数用于连接、操作和管理Redis数据库,本文给大家介绍redis-cli命令行工具的使用小结,感兴趣的... 目录基本连接参数基本连接方式连接远程服务器带密码连接操作与格式参数-r参数重复执行命令-i参数指定命

深入理解Redis大key的危害及解决方案

《深入理解Redis大key的危害及解决方案》本文主要介绍了深入理解Redis大key的危害及解决方案,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着... 目录一、背景二、什么是大key三、大key评价标准四、大key 产生的原因与场景五、大key影响与危

Redis主从复制的原理分析

《Redis主从复制的原理分析》Redis主从复制通过将数据镜像到多个从节点,实现高可用性和扩展性,主从复制包括初次全量同步和增量同步两个阶段,为优化复制性能,可以采用AOF持久化、调整复制超时时间、... 目录Redis主从复制的原理主从复制概述配置主从复制数据同步过程复制一致性与延迟故障转移机制监控与维

Redis过期键删除策略解读

《Redis过期键删除策略解读》Redis通过惰性删除策略和定期删除策略来管理过期键,惰性删除策略在键被访问时检查是否过期并删除,节省CPU开销但可能导致过期键滞留,定期删除策略定期扫描并删除过期键,... 目录1.Redis使用两种不同的策略来删除过期键,分别是惰性删除策略和定期删除策略1.1惰性删除策略

Linux(Centos7)安装Mysql/Redis/MinIO方式

《Linux(Centos7)安装Mysql/Redis/MinIO方式》文章总结:介绍了如何安装MySQL和Redis,以及如何配置它们为开机自启,还详细讲解了如何安装MinIO,包括配置Syste... 目录安装mysql安装Redis安装MinIO总结安装Mysql安装Redis搜索Red

Redis连接失败:客户端IP不在白名单中的问题分析与解决方案

《Redis连接失败:客户端IP不在白名单中的问题分析与解决方案》在现代分布式系统中,Redis作为一种高性能的内存数据库,被广泛应用于缓存、消息队列、会话存储等场景,然而,在实际使用过程中,我们可能... 目录一、问题背景二、错误分析1. 错误信息解读2. 根本原因三、解决方案1. 将客户端IP添加到Re

java如何分布式锁实现和选型

《java如何分布式锁实现和选型》文章介绍了分布式锁的重要性以及在分布式系统中常见的问题和需求,它详细阐述了如何使用分布式锁来确保数据的一致性和系统的高可用性,文章还提供了基于数据库、Redis和Zo... 目录引言:分布式锁的重要性与分布式系统中的常见问题和需求分布式锁的重要性分布式系统中常见的问题和需求