首页 > 编程语言 >Java中的司机抢单实现:并发问题与解决方案

Java中的司机抢单实现:并发问题与解决方案

时间:2024-08-21 13:24:04浏览次数:12  
标签:Java orderInfo 订单 wrapper 抢单 new 并发

文章目录


在共享经济的浪潮中,像滴滴打车这样的服务已经成为我们生活中不可或缺的一部分。对于司机和平台来说,抢单是一个关键环节,如何在保证系统高效运行的同时,确保抢单过程的公平与准确,是一个值得深入探讨的问题。在这篇博客中,我将带大家一起看看在Java中如何实现司机抢单的逻辑,并且如何解决可能存在的并发问题。

司机抢单的基础实现

首先,我们来看一下基础的司机抢单实现。这个方法通过Redis来判断订单是否存在,以减少数据库的压力。具体代码如下:

@Override
public Boolean robNewOrder(Long driverId, Long orderId) {
    // 判断订单是否存在,通过Redis,减少数据库压力
    String redisKey = RedisConstant.ORDER_ACCEPT_MARK + orderId;
    if (Boolean.FALSE.equals(redisTemplate.hasKey(redisKey))) {
        // 抢单失败
        throw new GuiguException(ResultCodeEnum.COB_NEW_ORDER_FAIL);
    }
    // 司机抢单
    // 修改订单表状态值为2:已经接单
    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);
    return true;
}

这个实现的思路是非常直观的:

  1. 首先,通过Redis来判断订单是否已经存在,这样做的好处是减少对数据库的直接访问,从而减轻数据库的压力。
  2. 然后,通过LambdaQueryWrapper查询订单,并将订单状态修改为“已接单”。
  3. 最后,删除Redis中的订单标识。

这种实现方式对于普通的业务场景已经足够了,但在高并发场景下可能会出现问题。比如,当多个司机同时抢同一个订单时,可能会导致订单状态更新的竞争,进而出现数据不一致的问题。

乐观锁解决并发问题

为了解决并发问题,我们可以引入乐观锁的思想。乐观锁不会像悲观锁那样锁住数据库记录,而是通过在更新时检查记录的状态是否发生变化,来确保数据的一致性。代码如下:

public Boolean robNewOrder1(Long driverId, Long orderId) {
    // 判断订单是否存在,通过Redis,减少数据库压力
    String redisKey = RedisConstant.ORDER_ACCEPT_MARK + orderId;
    if (Boolean.FALSE.equals(redisTemplate.hasKey(redisKey))) {
        // 抢单失败
        throw new GuiguException(ResultCodeEnum.COB_NEW_ORDER_FAIL);
    }
    // 司机抢单
    // 修改订单表状态值为2:已经接单
    LambdaQueryWrapper<OrderInfo> wrapper = new LambdaQueryWrapper<>();
    wrapper.eq(OrderInfo::getId, orderId);
    wrapper.eq(OrderInfo::getStatus, OrderStatus.WAITING_ACCEPT.getStatus());
    // 修改值
    OrderInfo orderInfo = new OrderInfo();
    orderInfo.setStatus(OrderStatus.ACCEPTED.getStatus());
    orderInfo.setDriverId(driverId);
    orderInfo.setAcceptTime(new Date());
    int rows = orderInfoMapper.update(orderInfo, wrapper);
    if (rows != 1) {
        throw new GuiguException(ResultCodeEnum.COB_NEW_ORDER_FAIL);
    }
    // 删除Redis中的标示
    redisTemplate.delete(redisKey);
    return true;
}

在这个版本中,我们通过增加对订单状态的判断,确保只有在订单状态是“等待接单”的情况下,才允许更新订单为“已接单”。这样做的好处是,避免了多个司机同时抢同一个订单时,可能产生的并发问题。

通过这种乐观锁的机制,即使在高并发的情况下,我们也能保证订单状态的更新是安全的。

总结

抢单是一个看似简单却充满挑战的功能,尤其是在高并发场景下,如何保证数据的一致性和系统的高效运行,是每个开发者必须面对的问题。在这篇博客中,我们首先实现了一个简单的抢单逻辑,随后引入乐观锁,解决了可能的并发问题。希望这些内容能对大家有所帮助,在实际项目中能更加从容地应对类似的问题。

标签:Java,orderInfo,订单,wrapper,抢单,new,并发
From: https://blog.csdn.net/Takumilove/article/details/141391072

相关文章

  • 如何深入学习Java:从基础到高级的系统指南
    Java作为一种面向对象、跨平台、稳健且广泛应用的编程语言,已经成为软件开发领域中的中流砥柱。从企业级应用到Android开发,从大数据处理到Web应用,Java无处不在。对于学习Java的人来说,掌握这门语言不仅需要扎实的基础,还需要逐步深入,理解其核心概念、掌握先进技术,并能够灵活运用于......
  • 函数方法_java
    1.方法概述1.1方法的概念方法(method)是程序中最小的执行单元注意:方法必须先创建才可以使用,该过程成为方法定义方法创建后并不是直接可以运行的,需要手动使用后,才执行,该过程成为方法调用2.方法的定义和调用2.1无参数方法定义和调用定义格式:publicstaticvoid方......
  • java学习记录第八周
    在Java中,字符串是通过`String`类来表示的,`String`类是不可变的,这意味着一旦一个字符串被创建,它的值就不能被改变。字符串的创建字符串可以通过以下两种方式创建:使用字符串字面量:Stringstr1="Hello";使用new关键字:Stringstr2=newString("Hello");使用字符串字面量......
  • 基于Springboot的宿舍管理系统(有报告)。Javaee项目,springboot项目。
    演示视频:基于Springboot的宿舍管理系统(有报告)。Javaee项目,springboot项目。资源下载:基于Springboot的宿舍管理系统(有报告)。Javaee项目,springboot项目。项目介绍:采用M(model)V(view)C(controller)三层体系结构,通过Spring+SpringBoot+Mybatis+Vue+Maven来实现。MyS......
  • 基于Springboot的疫情物资捐赠和分配系统(有报告)。Javaee项目,springboot项目。
    演示视频:基于Springboot的疫情物资捐赠和分配系统(有报告)。Javaee项目,springboot项目。资源下载:基于Springboot的疫情物资捐赠和分配系统(有报告)。Javaee项目,springboot项目。项目介绍:采用M(model)V(view)C(controller)三层体系结构,通过Spring+SpringBoot+Mybatis+V......
  • 桶排序算法及优化(java)
    目录1.1引言1.2桶排序的历史1.3桶排序的基本原理1.3.1工作流程1.3.2关键步骤1.4桶排序的Java实现1.4.1简单实现1.4.2优化实现1.4.3代码解释1.5桶排序的时间复杂度1.5.1分析1.5.2证明1.6桶排序的稳定性1.7著名案例1.7.1应用场景1.7.2具体案例1......
  • 【CSP:202312-1】仓库规划(Java)
    题目链接202312-1仓库规划题目描述求解思路暴力求解:由于数据量较小,对每个仓库进行遍历求解即可。需要注意只有一个仓库的特殊情况。(n=1......
  • 【CSP:202312-2】因子化简(Java)
    题目链接202312-2因子化简题目描述求解思路哈希表:利用哈希表记录下每个因数出现的次数。从222开始遍历,找出......
  • 1Java加强----异常
    1.异常体系1.1异常入门1.1运行时异常publicstaticvoidshow(){//int[]arr={1,2,3};//System.out.println(arr[3]);//.ArrayIndexOutOfBoundsException数组越界异常//Stringstr=null;System.out.println(str.length());//Nul......
  • 2Java加强-----泛型
    1.认识泛型publicclassGenericDemo1{publicstaticvoidmain(String[]args){//目标:认识泛型,搞清楚使用泛型的好处。ArrayListlist=newArrayList();list.add("java");list.add("php");list.add(23);l......