Redisson分布式锁与司机抢单的应用实践

devtools/2024/11/15 2:22:49/

文章目录

      • 场景介绍
      • 代码实现
      • 代码解析
      • 总结

在高并发场景下,如何保证数据的一致性和操作的原子性,是一个非常重要的课题。今天,我想跟大家分享一下在我们开发中的一个实际案例——司机抢单功能——是如何通过Redisson分布式锁来实现的。

场景介绍

假设有这么一个场景,某网约车平台上,有多个司机在同时抢同一个订单。为了保证订单不被多名司机同时抢到,我们需要一个有效的机制来控制并发操作。最简单粗暴的方式当然是数据库锁,但这种方式显然性能不高,在高并发下可能会导致数据库的压力剧增,进而拖慢系统响应速度。

这时候,Redis的分布式锁就派上用场了。Redisson是一个非常好用的Redis客户端,它提供了丰富的分布式工具,其中就包括分布式锁。

代码实现

在我们的robNewOrder方法中,我们使用Redisson的RLock来实现分布式锁,从而保证同一时间只有一个司机能成功抢到订单。

@Override
public Boolean robNewOrder(Long driverId, Long orderId) {// 判断订单是否存在,通过Redis减少数据库压力String redisKey = RedisConstant.ORDER_ACCEPT_MARK + orderId;if (!redisTemplate.hasKey(redisKey)) {// 抢单失败throw new GuiguException(ResultCodeEnum.COB_NEW_ORDER_FAIL);}// 创建锁RLock lock = redissonClient.getLock(RedisConstant.ROB_NEW_ORDER_LOCK + orderId);try {boolean flag = lock.tryLock(RedisConstant.ROB_NEW_ORDER_LOCK_WAIT_TIME,RedisConstant.ROB_NEW_ORDER_LOCK_LEASE_TIME,TimeUnit.SECONDS);// 司机抢单成功的逻辑if (flag) {if (!redisTemplate.hasKey(redisKey)) {// 抢单失败throw new GuiguException(ResultCodeEnum.COB_NEW_ORDER_FAIL);}// 更新订单状态为“已接单”LambdaQueryWrapper<OrderInfo> wrapper = new LambdaQueryWrapper<>();wrapper.eq(OrderInfo::getId, orderId);OrderInfo orderInfo = orderInfoMapper.selectOne(wrapper);orderInfo.setStatus(OrderStatus.ACCEPTED.getStatus());orderInfo.setDriverId(driverId);orderInfo.setAcceptTime(new Date());int rows = orderInfoMapper.updateById(orderInfo);if (rows != 1) {throw new GuiguException(ResultCodeEnum.COB_NEW_ORDER_FAIL);}// 删除Redis中的标示redisTemplate.delete(redisKey);}} catch (Exception e) {throw new GuiguException(ResultCodeEnum.COB_NEW_ORDER_FAIL);} finally {// 释放锁if (lock.isLocked()) {lock.unlock();}}return true;
}

代码解析

这段代码中有几个关键点:

  1. Redis缓存标识判断:通过redisTemplate.hasKey(redisKey)来判断订单是否存在。这样可以有效减少数据库的访问频率,降低系统压力。

  2. 分布式锁的创建与使用redissonClient.getLock()方法用于获取分布式锁,然后通过tryLock尝试获取锁。这里我们设置了锁的等待时间和租期,确保锁不会被长期占用,防止死锁。

  3. 订单状态更新:如果司机成功获取到锁,我们便可以安全地更新订单状态,并将司机的ID以及接单时间记录到订单信息中。

  4. 锁的释放:无论操作成功与否,最后都会在finally块中释放锁,保证锁的及时释放,避免造成锁的长时间占用。

总结

通过这段代码,我们可以看到,在高并发的环境下,合理使用分布式锁可以有效解决数据一致性问题,同时降低数据库压力。Redisson作为一个功能强大的Redis客户端,提供了丰富的分布式工具,大大简化了我们开发分布式系统的难度。
在实际开发中,除了锁机制外,我们还需要考虑锁的粒度、过期时间等细节,以避免死锁和性能问题。因此,合理设计和使用分布式锁,是我们在构建高并发系统时必须掌握的一项重要技能。


http://www.ppmy.cn/devtools/98239.html

相关文章

[Qt][Qt 文件]详细讲解

目录 1.输入输出设备类2.文件读写类3.文件和目录信息类 1.输入输出设备类 在Qt中&#xff0c;⽂件读写的类为QFile&#xff0c;其⽗类为QFileDevice QFileDevice提供了⽂件交互操作的底层功能QFileDevice的⽗类是QIODevice&#xff0c;其⽗类为QObject QIODevice是Qt中所有I/O…

Spark环境搭建-Local

目录 Local下的角色分布&#xff1a; Anaconda On Linux 安装 (单台服务器) 1.下载安装 2.国内源 下载Spark安装包 1.下载 2.解压 3.环境变量 测试 监控 Local下的角色分布&#xff1a; 资源管理&#xff1a; Master&#xff1a;Local进程本身 Worker&#xff1a;L…

linux centos 防火墙常用命令

1、开放端口 firewall-cmd --zonepublic --add-port80/tcp --permanent 1 2、查看某端口是否开放 firewall-cmd --query-port80/tcp 1 3、查看端口开启列表 firewall-cmd --list-port 1 4、重启防火墙 firewall-cmd --reload 1 5、关闭防火墙 systemctl stop firewalld.se…

【算法基础实验】图论-最小生成树-Prim的即时实现

理论知识 Prim算法是一种用于计算加权无向图的最小生成树&#xff08;MST, Minimum Spanning Tree&#xff09;的贪心算法。最小生成树是一个连通的无向图的子图&#xff0c;它包含所有的顶点且总权重最小。Prim算法从一个起始顶点开始&#xff0c;不断将权重最小的边加入生成…

结构开发笔记(五):solidworks软件(四):绘制36x36方块摄像头基座

若该文为原创文章&#xff0c;转载请注明原文出处 本文章博客地址&#xff1a;https://hpzwl.blog.csdn.net/article/details/141422131 长沙红胖子Qt&#xff08;长沙创微智科&#xff09;博文大全&#xff1a;开发技术集合&#xff08;包含Qt实用技术、树莓派、三维、OpenCV…

高并发登录模块

1. 配置⼀主⼆从mysql57 1. mycat对mysql8不完全⽀持 2. mysql8主从问题不⼤ get_pub_key1 1. gtids事务复制 2. 删除/etc/my.cnf 3. 同步data⽂件需要先停⽤mysql服务&#xff0c;删除data⽬录中的 auto.cnf 4. gtid模式以及经典模式都需要锁表 5. 开放mysql服务端⼝ 3. 添加…

NVF04M录音芯片在宠物喂食器的应用:录音播放功能,内置SPI闪存

在现代社会中&#xff0c;宠物已经成为人们生活中的一部分&#xff0c;而宠物喂食器作为宠物养护的重要工具&#xff0c;也越来越受到人们的关注。为了满足人们对宠物喂食器的多样化需求&#xff0c;九芯电子供应商研发了一款NVF04M录音芯片。它在宠物喂食器中的作用主要是提供…

【芯片设计- RTL 数字逻辑设计入门 9.3 -- 为什么 FPGA 的效率低于 ASIC?】

文章目录 FPGA 和 ASIC 概述FPGA&#xff08;Field-Programmable Gate Array&#xff09;ASIC&#xff08;Application-Specific Integrated Circuit&#xff09;FPGA 与 ASIC 的对比总结逻辑单元(FPGA的基础模块)FPGA路由信号标准单元&#xff1a;ASIC的构建模块ASIC布局 FPGA…