当前位置: 首页 > article >正文

乐观锁解决库存超卖问题

public BaseResult creatOneOrder(FlightOrderServiceImpl orderService, List<Map<String, String>> passengers,Map<String, String> selectFlightMap,String account) throws Exception {
            //如果是单程
            //判断座位数是否>=1
            //是的话就直接减库存
            //不是就return 201,库存不够

            int k=0;

            FlightSeat seat = seatService.getById(selectFlightMap.get("seatId"));
            if(seat.getRestNum()<1){
                return new BaseResult(201,"库存不够了");
            }

            seat.setRestNum(seat.getRestNum()-1);
            boolean updateResult = seatService.updateById(seat);
            if(!updateResult){
                //如果更新失败
                //说明在更新前有其他人已经对该行剩余量进行了修改
                //就再试一次,先判断库存
                int maxRetries = 5; //最大重试次数
                int retryCount = 0;

                while (retryCount < maxRetries) {
                    // 获取最新的座位信息
                    FlightSeat updatedSeat = seatService.getById(selectFlightMap.get("seatId"));

                    // 检查座位是否仍然可用
                    if (updatedSeat.getRestNum() < 1) {
                        return new BaseResult(201, "库存不够了");
                    }

                    // 尝试更新座位信息
                    updatedSeat.setRestNum(updatedSeat.getRestNum() - 1);
                    boolean retryUpdateResult = seatService.updateById(updatedSeat);

                    // 检查更新操作的结果
                    if (retryUpdateResult) {
                        // 成功更新,生成订单,跳出循环
                        k=1;
                        break;

                    } else {
                        // 增加重试计数并进行下一次尝试
                        retryCount++;
                    }

                    if (retryCount == maxRetries) {
                        return new BaseResult(202, "更新失败,重试次数已达上限");
                    }
                }


            }
            else {
                k =1;
            }

            if(k==1){//k=1说明库存成功减少了

                FlightOrder Order = new FlightOrder();
                // 获取当前时间
                LocalDateTime currentTime = LocalDateTime.now();

                // 如果你想以特定格式输出当前时间,可以使用 DateTimeFormatter
                DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
                String formattedCurrentTime = currentTime.format(formatter);
                Order.setDate(formattedCurrentTime);

                // 设置超时时间为当前时间的15分钟后
                LocalDateTime timeoutTime = currentTime.plusMinutes(15);
                String formattedTimeoutTime = timeoutTime.format(formatter);
                Order.setTimeout(formattedTimeoutTime);


                Order.setOrderId(String.valueOf(new SnowUtil(0,0).getId()));


//                redisTemplate.opsForValue().set(Order.getOrderId(), Order.getOrderId(), 15, TimeUnit.MINUTES);
                redisTemplate.opsForValue().set(Order.getOrderId(), Order.getOrderId(), 15, TimeUnit.MINUTES);

                Flight flight = new Flight();
                flight = flightService.getById(selectFlightMap.get("flightId"));

                Order.setFlightCode(flight.getFlightCode());
                Order.setStage("待支付");
                Order.setWay("单程");
                Order.setUserId(account);


                Air air = airService.getById(flight.getAirId());
                Order.setPrice(seat.getPrice());
                Order.setAllPrice(seat.getPrice());
                Order.setSeatType(seat.getSeatType());
                Order.setDepCity(flight.getDepCity());
                Order.setDepDate(flight.getDepDate());
                Order.setDepTime(flight.getDepTime());
                Order.setArrCity(flight.getArrCity());
                Order.setArrDate(flight.getArrDate());
                Order.setArrTime(flight.getArrTime());
                Order.setDepAirport(flight.getDepAirport());
                Order.setArrAirport(flight.getArrAirport());
                Order.setAirlineName(flight.getAirlineName());
                Order.setAirType(air.getType());


                orderService.save(Order);


                for (Map<String, String> pas : passengers) {
                    FlightPassenger passenger = new FlightPassenger();
                    passenger.setOrderId(Order.getOrderId());
                    passenger.setName(pas.get("name"));
                    passenger.setIdentityId(pas.get("sfz"));
                    passenger.setPhone(pas.get("phone"));
                    passengerService.save(passenger);
                }
                return new BaseResult(200,"支付成功",Order.getOrderId());
            }
            else return new BaseResult(202,"库存不够或者重试次数达到上限");




    }

往返票

 @Transactional
    public BaseResult creatTwoOrder(FlightOrderServiceImpl orderService,List<Map<String, String>> passengers,Map<String, String> selectFlightMap,String account) throws Exception {


            //            座位
            int k1=0,k2=0;
            FlightSeat seat = seatService.getById(selectFlightMap.get("goSeatId"));
            FlightSeat seatback = seatService.getById(selectFlightMap.get("backSeatId"));


            //先判断库存
            if(seat.getRestNum()<1||seatback.getRestNum()<1){
                return new BaseResult(201,"库存不够了");
            }

            //如果库存都够
            seat.setRestNum(seat.getRestNum()-1);
            boolean updateResult = seatService.updateById(seat);
            if(!updateResult){//如果更新失败
                int max =5;
                int cnt=0;
                while(cnt<max){
                    //先判断库存
                    FlightSeat newSeat = seatService.getById(selectFlightMap.get("goSeatId"));
                    if(newSeat.getRestNum()<1){
                        return new BaseResult(201,"库存不够了");
                    }

                    //如果库存足够
                    newSeat.setRestNum(newSeat.getRestNum()-1);
                    boolean updateSeatResult = seatService.updateById(newSeat);
                    if(updateSeatResult){
                        //成功
                        k1 =1;
                        break;
                    }
                    else {
                        //修改库存又失败了,有其他线程已经将这行记录的值进行了修改
                        cnt++;
                    }

                    if(cnt==max){
                        return new BaseResult(202,"重试次数已经达到上限");
                    }
                }

            }
            else {
                //一次成功
                k1 =1;
            }

            //到这里的话就说明去程的票减库存已经成功了
            //开始买返程的票
            seatback.setRestNum(seatback.getRestNum()-1);
            boolean backSeatResult = seatService.updateById(seatback);
            if(!backSeatResult){
                //如果更新失败
                int max1 =5;
                int cnt1 =0;
                while (cnt1<max1){
                    FlightSeat newSeatback = seatService.getById(selectFlightMap.get("backSeatId"));

                    if(newSeatback.getRestNum()<1){
                        //回滚去程的票数
                        TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                        return new BaseResult(202,"库存不够了");
                    }

                    //如果库存足够
                    boolean result = seatService.updateById(newSeatback);
                    if(result){
                        k2=1;
                        break;
                    }
                    else {
                        cnt1++;
                    }

                    if(cnt1==max1){
                        //首先要回滚去程的库存
                        TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                        return new BaseResult(202,"达到尝试上限");
                    }
                }

            }
            else {
                k2=1;
            }
            if(k1==1&&k2==1){
                FlightOrder Order = new FlightOrder();
                // 获取当前时间
                LocalDateTime currentTime = LocalDateTime.now();

                // 如果你想以特定格式输出当前时间,可以使用 DateTimeFormatter
                DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
                String formattedCurrentTime = currentTime.format(formatter);
                Order.setDate(formattedCurrentTime);

                // 设置超时时间为当前时间的15分钟后
                LocalDateTime timeoutTime = currentTime.plusMinutes(15);
                String formattedTimeoutTime = timeoutTime.format(formatter);
                Order.setTimeout(formattedTimeoutTime);


                Order.setOrderId(String.valueOf(new SnowUtil(0,0).getId()));
                redisTemplate.opsForValue().set(Order.getOrderId(), Order.getOrderId(), 15, TimeUnit.MINUTES);


                //            获取数据
                Flight flight1 = flightService.getById(selectFlightMap.get("goId"));

                Air air1 = airService.getById(flight1.getAirId());
                Order.setDepCity(flight1.getDepCity());
                Order.setDepDate(flight1.getDepDate());
                Order.setDepTime(flight1.getDepTime());
                Order.setArrCity(flight1.getArrCity());
                Order.setArrDate(flight1.getArrDate());
                Order.setArrTime(flight1.getArrTime());
                Order.setDepAirport(flight1.getDepAirport());
                Order.setArrAirport(flight1.getArrAirport());
                Order.setAirlineName(flight1.getAirlineName());
                Order.setAirType(air1.getType());


//            订单对象

                Order.setFlightCode(flight1.getFlightCode());
                Order.setStage("待支付");
                Order.setWay("往返");
                Order.setUserId(account);



                Order.setPrice(seat.getPrice());
                Order.setSeatType(seat.getSeatType());

                Flight flight2 = flightService.getById(selectFlightMap.get("backId"));
                Air air2 = airService.getById(flight2.getAirId());
                Order.setBackDepCity(flight2.getDepCity());
                Order.setBackDepDate(flight2.getDepDate());
                Order.setBackDepTime(flight2.getDepTime());
                Order.setBackArrCity(flight2.getArrCity());
                Order.setBackArrDate(flight2.getArrDate());
                Order.setBackArrTime(flight2.getArrTime());
                Order.setBackDepAirport(flight2.getDepAirport());
                Order.setBackArrAirport(flight2.getArrAirport());
                Order.setBackAirlineName(flight2.getAirlineName());
                Order.setBackAirType(air2.getType());


                Order.setBackPrice(seatback.getPrice());
                Order.setAllPrice(seat.getPrice()+seatback.getPrice());

                Order.setBackFlightCode(flight2.getFlightCode());
                Order.setBackSeatType(seatback.getSeatType());
                orderService.save(Order);

                for (Map<String, String> pas : passengers) {
                    FlightPassenger passenger = new FlightPassenger();
                    passenger.setOrderId(Order.getOrderId());
                    passenger.setName(pas.get("name"));
                    passenger.setIdentityId(pas.get("sfz"));
                    passenger.setPhone(pas.get("phone"));
                    passengerService.save(passenger);
                }

                return new BaseResult(200,"支付成功",Order.getOrderId());
            }
            else {
                TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                return new BaseResult(202, "库存不够或者达到重试次数上限");

            }


    }


http://www.kler.cn/a/145647.html

相关文章:

  • Unity自学之旅04
  • Golang之Context详解
  • 5G网络下移动机器人的图像和指令传输用于远程操作
  • QT:QTabWidget设置tabPosition为West时,文字向上
  • Excel打印技巧
  • 【2024年华为OD机试】(C/D卷,200分)- 5G网络建设 (JavaScriptJava PythonC/C++)
  • 【超强笔记软件】Obsidian如何实现免费无限流量无套路云同步?
  • mybatis的使用,mybatis的实现原理,mybatis的优缺点,MyBatis缓存,MyBatis运行的原理,MyBatis的编写方式
  • ESP32网络开发实例-远程Web串口监视器
  • 声音响度、声压级计权(A B C)实现
  • 高品质MP3音频解码语音芯片WT2003Hx的特征优势与应用场景
  • WebSocket了解
  • 论文公式和代码对应
  • C语言数据类型和变量
  • 机器学习/sklearn笔记:MeanShift
  • SkyWalking全景解析:从原理到实现的分布式追踪之旅
  • DY点赞、搜索功能测试用例设计
  • 【刷题笔记】接雨水||暴力通过||符合思维方式
  • JC/T 456-2015 陶瓷马赛克检测
  • 【单调栈】子数组的最小值之和
  • Presto+Alluxio数据平台实战
  • IDM(Internet Download Manager)PC版提升下载速度与效率的利器
  • uniapp+vue基于Android的校园二手跳蚤市场的设计与实现 微信小程序
  • 18.天气小案例
  • 电子学会C/C++编程等级考试2021年06月(三级)真题解析
  • SELinux零知识学习三十、SELinux策略语言之角色和用户(1)