【JAVA+Redis分布式锁解决业务库存超卖】


前言

目前基本上的电商业务都会有购买商品多人同时购买或者秒杀业务场景,这里介绍在这种业务场景下如何防止出现商品超卖的现象。


一、超卖是什么?

当商品库存接近0时,此时多个买家同时下单付款购买同一商品,买家成功购买的商品数量大于商品库存数量,将会出现超卖现象,超卖现象本质上就是买到了比仓库中的数量更多的商品。

二、实现步骤

1.引入依赖

在 pom.xml  引入依赖

代码如下(示例):

<dependency>
    <groupId>org.redisson</groupId>
    <artifactId>redisson</artifactId>
    <version>3.10.6</version>
</dependency>

2.代码实现

2.1:yml配置:

spring:
  #redis缓存配置
  redis:
    host: 127.0.0.1
    port: 6379
    password: 123456
    timeout: 60000         #redis 连接超时时间ms
    database: 11           #指定使用哪个reids库

 2.2:创建RedissonUtils工具类

import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.concurrent.TimeUnit;

/**
 * @description :Redisson工具类
 */
@Component
public class RedissonUtils {

    private static RedissonClient redissonClient;

    @Autowired
    public void setRedissonClient(RedissonClient redissonClient) {
        RedissonUtils.redissonClient = redissonClient;
    }

    /**
     * 加锁
     * @param lockKey
     * @return
     */
    public RLock lock(String lockKey) {
        RLock lock = redissonClient.getLock(lockKey);
        lock.lock();
        return lock;
    }

    /**
     * 获取锁
     * @param lockKey
     * @return
     */
    public RLock getLock(String lockKey) {
        RLock lock = redissonClient.getLock(lockKey);
        return lock;
    }

    /**
     * 释放锁
     *
     * @param lockKey
     */
    public void unlock(String lockKey) {
        RLock lock = redissonClient.getLock(lockKey);
        lock.unlock();
    }

    /**
     * 释放锁
     * @param lock
     */
    public void unlock(RLock lock) {
        lock.unlock();
    }

    /**
     * 此方法是阻塞获取锁的方式,如果当前锁被其他线程持有,则当前线程会一直阻塞等待获取锁,直到获取到锁或者发生超时或中断等情况才会结束等待。该方法获取到锁之后可以保证线程对共享资源的访问是互斥的,
     * 适用于需要确保共享资源只能被一个线程访问的场景。Redisson 的 lock() 方法支持可重入锁和公平锁等特性,
     * 可以更好地满足多线程并发访问的需求。
     *
     * 带超时的锁
     * @param lockKey
     * @param timeout 超时时间   单位:秒
     */
    public RLock lock(String lockKey, int timeout) {
        RLock lock = redissonClient.getLock(lockKey);
        lock.lock(timeout, TimeUnit.SECONDS);
        return lock;
    }

    /**
     * 此方法是阻塞获取锁的方式,如果当前锁被其他线程持有,则当前线程会一直阻塞等待获取锁,直到获取到锁或者发生超时或中断等情况才会结束等待。该方法获取到锁之后可以保证线程对共享资源的访问是互斥的,
     * 适用于需要确保共享资源只能被一个线程访问的场景。Redisson 的 lock() 方法支持可重入锁和公平锁等特性,
     * 可以更好地满足多线程并发访问的需求。
     *
     * 带超时的锁
     * @param lockKey
     * @param unit    时间单位
     * @param timeout 超时时间
     */
    public RLock lock(String lockKey, int timeout, TimeUnit unit) {
        RLock lock = redissonClient.getLock(lockKey);
        lock.lock(timeout, unit);
        return lock;
    }

    /**
     *  此方法是一种非阻塞获取锁的方式,在尝试获取锁时不会阻塞当前线程,而是立即返回获取锁的结果,如果获取成功则返回 true,
     *  否则返回 false。Redisson 的 tryLock() 方法支持加锁时间限制、等待时间限制以及可重入等特性,
     *  可以更好地控制获取锁的过程和等待时间,避免程序出现长时间无法响应等问题。
     *
     * 尝试获取锁
     * @param lockKey
     * @param waitTime  最多等待时间 单位:秒
     * @param leaseTime 上锁后自动释放锁时间 单位:秒
     * @return
     */
    public boolean tryLock(String lockKey, int waitTime, int leaseTime) {
        RLock lock = redissonClient.getLock(lockKey);
        try {
            return lock.tryLock(waitTime, leaseTime, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            return false;
        }
    }


    /**
     *  此方法是一种非阻塞获取锁的方式,在尝试获取锁时不会阻塞当前线程,而是立即返回获取锁的结果,如果获取成功则返回 true,
     *  否则返回 false。Redisson 的 tryLock() 方法支持加锁时间限制、等待时间限制以及可重入等特性,
     *  可以更好地控制获取锁的过程和等待时间,避免程序出现长时间无法响应等问题。
     *
     * 尝试获取锁
     * @param lockKey
     * @param unit      时间单位
     * @param waitTime  最多等待时间
     * @param leaseTime 上锁后自动释放锁时间
     * @return
     */
    public boolean tryLock(String lockKey, TimeUnit unit, int waitTime, int leaseTime) {
        RLock lock = redissonClient.getLock(lockKey);
        try {
            return lock.tryLock(waitTime, leaseTime, unit);
        } catch (InterruptedException e) {
            return false;
        }
    }
}

 2.3:业务代码

package com.absen.b2b.kaihuile.module.hotel.controller.platform.visitor;

import com.absen.b2b.kaihuile.common.base.KaiHuiLeApiResponse;
import com.absen.b2b.kaihuile.common.redis.utils.RedissonUtils;
import com.absen.b2b.kaihuile.module.hotel.controller.publics.visitor.PublicVisitorHallInquiryUserJoinController;
import com.absen.b2b.kaihuile.module.hotel.dto.QuoteBeforeHallContrastQueryDto;
import com.absen.b2b.kaihuile.module.hotel.entity.HallBiddingEntity;
import com.absen.b2b.kaihuile.module.hotel.entity.HallInquiryUserJoinEntity;
import com.absen.b2b.kaihuile.module.hotel.service.HallBiddingService;
import com.absen.b2b.kaihuile.module.hotel.service.InquiryCustomerArchivesService;
import com.absen.b2b.kaihuile.module.hotel.vo.QuoteBeforeHallContrastVo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.util.List;

/**
 * @Description: 测试下单减库存超卖
 * @Author: rong.jiang
 * @Date: 2023/6/16
 */
@RestController
@RequestMapping("platform/api/visitor/hall/userJoin")
public class PlatformVisitorHallInquiryUserJoinController extends PublicVisitorHallInquiryUserJoinController {


    @Autowired
    private RedissonUtils redissonUtils;

    @Autowired
    private HallBiddingService hallBiddingService;

    /**
     * 未使用加锁(出现超卖情况)
     *
     * @param goodsId 商品id
     * @return
     */
    @GetMapping(value = "/lock/chaomai/{goodsId}")
    public KaiHuiLeApiResponse chaomai(@ApiParam(value = "商品id") @PathVariable(value = "goodsId") String goodsId) {
        //商品信息
        HallBiddingEntity hallBidding = hallBiddingService.getById(goodsId);
        if (0 == hallBidding.getBoardNumber()) {
            throw new RuntimeException("商品数量库存不足");
        }
        //1.创建业务订单数据逻辑,业务代码忽略

        //2.扣减商品库存
        hallBidding.setBoardNumber(hallBidding.getBoardNumber() - 1);
        System.out.println("未使用加锁^^设置库存:" + hallBidding.getBoardNumber());
        hallBiddingService.updateById(hallBidding);
        return KaiHuiLeApiResponse.ok();
    }

    /**
     * 使用加锁(防止超卖情况)
     *
     * @param goodsId 商品id
     * @return
     */
    @GetMapping(value = "/lock/nochaomai/{goodsId}")
    public KaiHuiLeApiResponse nochaomai(@ApiParam(value = "商品id") @PathVariable(value = "goodsId") String goodsId) {
        Boolean locked = false;
        try {
            //加锁,设置锁超时时间(120秒),等待锁的时间(10秒)
            locked = redissonUtils.tryLock(goodsId, 120, 10);
            if (!locked) {
                return KaiHuiLeApiResponse.fail("当前商品库存有其他订单在操作");
            }
            //商品信息
            HallBiddingEntity hallBidding = hallBiddingService.getById(goodsId);
            if (0 == hallBidding.getBoardNumber()) {
                throw new RuntimeException("商品数量库存不足");
            }
            //1.创建业务订单数据逻辑,业务代码忽略


            //2.扣减商品库存
            hallBidding.setBoardNumber(hallBidding.getBoardNumber() - 1);
            System.out.println("使用加锁^^设置库存:" + hallBidding.getBoardNumber());
            hallBiddingService.updateById(hallBidding);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (locked) {
                redissonUtils.unlock(goodsId);
            }
        }
        return KaiHuiLeApiResponse.ok();
    }

}

三、测试

1.使用测试工具测试

本例使用的是Apipost工具

测试工具下载地址:https://www.apipost.cn/download.html

1.1:测试:超卖情况

初始化数据库商品库存为50

并发数为100,100个用户同时下单模拟

控制台输出结果:输出显示一个商品都被卖了多次情况

未使用加锁^^设置库存:49
未使用加锁^^设置库存:49
2023-08-12 11:09:52.574 b2b-kaihuile-logback http-nio-5000-exec-52 DEBUG c.a.b.k.m.h.m.H.selectById - ==> Parameters: 1001(String)
2023-08-12 11:09:52.574 b2b-kaihuile-logback http-nio-5000-exec-19 DEBUG c.a.b.k.m.h.m.H.selectById - ==> Parameters: 1001(String)
未使用加锁^^设置库存:49
未使用加锁^^设置库存:49
未使用加锁^^设置库存:49
未使用加锁^^设置库存:49
未使用加锁^^设置库存:49
未使用加锁^^设置库存:49
2023-08-12 11:09:52.574 b2b-kaihuile-logback http-nio-5000-exec-94 DEBUG c.a.b.k.m.h.m.H.selectById - ==> Parameters: 1001(String)
未使用加锁^^设置库存:49
未使用加锁^^设置库存:49
未使用加锁^^设置库存:49
未使用加锁^^设置库存:49
未使用加锁^^设置库存:49

数据库库存变化结果:初始化50,执行后没有将库存清空,正常情况100人同时下单库存会被抢完

1.2:测试:防止超卖情况

初始化数据库商品库存为50

并发数为100,100个用户同时下单模拟

控制台输出结果:输出显示未出现超卖情况

使用加锁^^设置库存:49
2023-08-12 11:29:42.695 b2b-kaihuile-logback http-nio-5000-exec-183 DEBUG c.a.b.k.m.h.m.H.updateById - ==>  Preparing: UPDATE hms_hall_bidding SET inquiry_detail_id=?, inquiry_id=?, corresponding_period=?, active_time=?, big_bed_number=?, double_bed_number=?, board_number=?, latest_time=?, active_type=?, previously_used_hotel=?, accommodation_budget=?, other=?, creator_id=?, creator_name=?, creator_time=?, editor_id=?, editor_name=?, editor_time=? WHERE hall_bidding_id=? AND is_delete=0 
2023-08-12 11:29:42.696 b2b-kaihuile-logback http-nio-5000-exec-183 DEBUG c.a.b.k.m.h.m.H.updateById - ==> Parameters: (String), (String), (String), 2023-07-20 00:00:00.0(Timestamp), 0(Integer), 0(Integer), 49(Integer), 2023-07-19 00:00:00.0(Timestamp), 0(Integer), 无(String), 200(Integer), 祝你新年快乐了(String), cf68f402eef7ca15a29142a8bc944e4f(String), 应俊(String), 2023-07-04 14:47:35.0(Timestamp), cf68f402eef7ca15a29142a8bc944e4f(String), 应俊(String), 2023-08-12 11:29:42.694(Timestamp), 1001(String)
2023-08-12 11:29:42.701 b2b-kaihuile-logback http-nio-5000-exec-183 DEBUG c.a.b.k.m.h.m.H.updateById - <==    Updates: 1
2023-08-12 11:29:42.706 b2b-kaihuile-logback http-nio-5000-exec-167 DEBUG c.a.b.k.m.h.m.H.selectById - ==>  Preparing: SELECT hall_bidding_id,inquiry_detail_id,inquiry_id,corresponding_period,active_time,big_bed_number,double_bed_number,board_number,latest_time,active_type,previously_used_hotel,accommodation_budget,other,is_delete,creator_id,creator_name,creator_time,editor_id,editor_name,editor_time FROM hms_hall_bidding WHERE hall_bidding_id=? AND is_delete=0 
2023-08-12 11:29:42.706 b2b-kaihuile-logback http-nio-5000-exec-167 DEBUG c.a.b.k.m.h.m.H.selectById - ==> Parameters: 1001(String)
2023-08-12 11:29:42.708 b2b-kaihuile-logback http-nio-5000-exec-167 DEBUG c.a.b.k.m.h.m.H.selectById - <==      Total: 1
使用加锁^^设置库存:48
2023-08-12 11:29:42.709 b2b-kaihuile-logback http-nio-5000-exec-167 DEBUG c.a.b.k.m.h.m.H.updateById - ==>  Preparing: UPDATE hms_hall_bidding SET inquiry_detail_id=?, inquiry_id=?, corresponding_period=?, active_time=?, big_bed_number=?, double_bed_number=?, board_number=?, latest_time=?, active_type=?, previously_used_hotel=?, accommodation_budget=?, other=?, creator_id=?, creator_name=?, creator_time=?, editor_id=?, editor_name=?, editor_time=? WHERE hall_bidding_id=? AND is_delete=0 
2023-08-12 11:29:42.710 b2b-kaihuile-logback http-nio-5000-exec-167 DEBUG c.a.b.k.m.h.m.H.updateById - ==> Parameters: (String), (String), (String), 2023-07-20 00:00:00.0(Timestamp), 0(Integer), 0(Integer), 48(Integer), 2023-07-19 00:00:00.0(Timestamp), 0(Integer), 无(String), 200(Integer), 祝你新年快乐了(String), cf68f402eef7ca15a29142a8bc944e4f(String), 应俊(String), 2023-07-04 14:47:35.0(Timestamp), cf68f402eef7ca15a29142a8bc944e4f(String), 应俊(String), 2023-08-12 11:29:42.709(Timestamp), 1001(String)
2023-08-12 11:29:42.715 b2b-kaihuile-logback http-nio-5000-exec-167 DEBUG c.a.b.k.m.h.m.H.updateById - <==    Updates: 1
2023-08-12 11:29:42.719 b2b-kaihuile-logback http-nio-5000-exec-125 DEBUG c.a.b.k.m.h.m.H.selectById - ==>  Preparing: SELECT hall_bidding_id,inquiry_detail_id,inquiry_id,corresponding_period,active_time,big_bed_number,double_bed_number,board_number,latest_time,active_type,previously_used_hotel,accommodation_budget,other,is_delete,creator_id,creator_name,creator_time,editor_id,editor_name,editor_time FROM hms_hall_bidding WHERE hall_bidding_id=? AND is_delete=0 
2023-08-12 11:29:42.719 b2b-kaihuile-logback http-nio-5000-exec-125 DEBUG c.a.b.k.m.h.m.H.selectById - ==> Parameters: 1001(String)
2023-08-12 11:29:42.723 b2b-kaihuile-logback http-nio-5000-exec-125 DEBUG c.a.b.k.m.h.m.H.selectById - <==      Total: 1
使用加锁^^设置库存:47
2023-08-12 11:29:42.724 b2b-kaihuile-logback http-nio-5000-exec-125 DEBUG c.a.b.k.m.h.m.H.updateById - ==>  Preparing: UPDATE hms_hall_bidding SET inquiry_detail_id=?, inquiry_id=?, corresponding_period=?, active_time=?, big_bed_number=?, double_bed_number=?, board_number=?, latest_time=?, active_type=?, previously_used_hotel=?, accommodation_budget=?, other=?, creator_id=?, creator_name=?, creator_time=?, editor_id=?, editor_name=?, editor_time=? WHERE hall_bidding_id=? AND is_delete=0 
2023-08-12 11:29:42.724 b2b-kaihuile-logback http-nio-5000-exec-125 DEBUG c.a.b.k.m.h.m.H.updateById - ==> Parameters: (String), (String), (String), 2023-07-20 00:00:00.0(Timestamp), 0(Integer), 0(Integer), 47(Integer), 2023-07-19 00:00:00.0(Timestamp), 0(Integer), 无(String), 200(Integer), 祝你新年快乐了(String), cf68f402eef7ca15a29142a8bc944e4f(String), 应俊(String), 2023-07-04 14:47:35.0(Timestamp), cf68f402eef7ca15a29142a8bc944e4f(String), 应俊(String), 2023-08-12 11:29:42.723(Timestamp), 1001(String)
2023-08-12 11:29:42.727 b2b-kaihuile-logback http-nio-5000-exec-125 DEBUG c.a.b.k.m.h.m.H.updateById - <==    Updates: 1
2023-08-12 11:29:42.731 b2b-kaihuile-logback http-nio-5000-exec-141 DEBUG c.a.b.k.m.h.m.H.selectById - ==>  Preparing: SELECT hall_bidding_id,inquiry_detail_id,inquiry_id,corresponding_period,active_time,big_bed_number,double_bed_number,board_number,latest_time,active_type,previously_used_hotel,accommodation_budget,other,is_delete,creator_id,creator_name,creator_time,editor_id,editor_name,editor_time FROM hms_hall_bidding WHERE hall_bidding_id=? AND is_delete=0 
2023-08-12 11:29:42.732 b2b-kaihuile-logback http-nio-5000-exec-141 DEBUG c.a.b.k.m.h.m.H.selectById - ==> Parameters: 1001(String)
2023-08-12 11:29:42.734 b2b-kaihuile-logback http-nio-5000-exec-141 DEBUG c.a.b.k.m.h.m.H.selectById - <==      Total: 1
使用加锁^^设置库存:46
2023-08-12 11:29:42.735 b2b-kaihuile-logback http-nio-5000-exec-141 DEBUG c.a.b.k.m.h.m.H.updateById - ==>  Preparing: UPDATE hms_hall_bidding SET inquiry_detail_id=?, inquiry_id=?, corresponding_period=?, active_time=?, big_bed_number=?, double_bed_number=?, board_number=?, latest_time=?, active_type=?, previously_used_hotel=?, accommodation_budget=?, other=?, creator_id=?, creator_name=?, creator_time=?, editor_id=?, editor_name=?, editor_time=? WHERE hall_bidding_id=? AND is_delete=0 
2023-08-12 11:29:42.736 b2b-kaihuile-logback http-nio-5000-exec-141 DEBUG c.a.b.k.m.h.m.H.updateById - ==> Parameters: (String), (String), (String), 2023-07-20 00:00:00.0(Timestamp), 0(Integer), 0(Integer), 46(Integer), 2023-07-19 00:00:00.0(Timestamp), 0(Integer), 无(String), 200(Integer), 祝你新年快乐了(String), cf68f402eef7ca15a29142a8bc944e4f(String), 应俊(String), 2023-07-04 14:47:35.0(Timestamp), cf68f402eef7ca15a29142a8bc944e4f(String), 应俊(String), 2023-08-12 11:29:42.735(Timestamp), 1001(String)
2023-08-12 11:29:42.739 b2b-kaihuile-logback http-nio-5000-exec-141 DEBUG c.a.b.k.m.h.m.H.updateById - <==    Updates: 1
2023-08-12 11:29:42.742 b2b-kaihuile-logback http-nio-5000-exec-172 DEBUG c.a.b.k.m.h.m.H.selectById - ==>  Preparing: SELECT hall_bidding_id,inquiry_detail_id,inquiry_id,corresponding_period,active_time,big_bed_number,double_bed_number,board_number,latest_time,active_type,previously_used_hotel,accommodation_budget,other,is_delete,creator_id,creator_name,creator_time,editor_id,editor_name,editor_time FROM hms_hall_bidding WHERE hall_bidding_id=? AND is_delete=0 
2023-08-12 11:29:42.743 b2b-kaihuile-logback http-nio-5000-exec-172 DEBUG c.a.b.k.m.h.m.H.selectById - ==> Parameters: 1001(String)
2023-08-12 11:29:42.744 b2b-kaihuile-logback http-nio-5000-exec-172 DEBUG c.a.b.k.m.h.m.H.selectById - <==      Total: 1
使用加锁^^设置库存:45
2023-08-12 11:29:42.745 b2b-kaihuile-logback http-nio-5000-exec-172 DEBUG c.a.b.k.m.h.m.H.updateById - ==>  Preparing: UPDATE hms_hall_bidding SET inquiry_detail_id=?, inquiry_id=?, corresponding_period=?, active_time=?, big_bed_number=?, double_bed_number=?, board_number=?, latest_time=?, active_type=?, previously_used_hotel=?, accommodation_budget=?, other=?, creator_id=?, creator_name=?, creator_time=?, editor_id=?, editor_name=?, editor_time=? WHERE hall_bidding_id=? AND is_delete=0 
2023-08-12 11:29:42.746 b2b-kaihuile-logback http-nio-5000-exec-172 DEBUG c.a.b.k.m.h.m.H.updateById - ==> Parameters: (String), (String), (String), 2023-07-20 00:00:00.0(Timestamp), 0(Integer), 0(Integer), 45(Integer), 2023-07-19 00:00:00.0(Timestamp), 0(Integer), 无(String), 200(Integer), 祝你新年快乐了(String), cf68f402eef7ca15a29142a8bc944e4f(String), 应俊(String), 2023-07-04 14:47:35.0(Timestamp), cf68f402eef7ca15a29142a8bc944e4f(String), 应俊(String), 2023-08-12 11:29:42.745(Timestamp), 1001(String)
2023-08-12 11:29:42.749 b2b-kaihuile-logback http-nio-5000-exec-172 DEBUG c.a.b.k.m.h.m.H.updateById - <==    Updates: 1
2023-08-12 11:29:42.752 b2b-kaihuile-logback http-nio-5000-exec-177 DEBUG c.a.b.k.m.h.m.H.selectById - ==>  Preparing: SELECT hall_bidding_id,inquiry_detail_id,inquiry_id,corresponding_period,active_time,big_bed_number,double_bed_number,board_number,latest_time,active_type,previously_used_hotel,accommodation_budget,other,is_delete,creator_id,creator_name,creator_time,editor_id,editor_name,editor_time FROM hms_hall_bidding WHERE hall_bidding_id=? AND is_delete=0 
2023-08-12 11:29:42.753 b2b-kaihuile-logback http-nio-5000-exec-177 DEBUG c.a.b.k.m.h.m.H.selectById - ==> Parameters: 1001(String)
2023-08-12 11:29:42.755 b2b-kaihuile-logback http-nio-5000-exec-177 DEBUG c.a.b.k.m.h.m.H.selectById - <==      Total: 1
使用加锁^^设置库存:44
2023-08-12 11:29:42.756 b2b-kaihuile-logback http-nio-5000-exec-177 DEBUG c.a.b.k.m.h.m.H.updateById - ==>  Preparing: UPDATE hms_hall_bidding SET inquiry_detail_id=?, inquiry_id=?, corresponding_period=?, active_time=?, big_bed_number=?, double_bed_number=?, board_number=?, latest_time=?, active_type=?, previously_used_hotel=?, accommodation_budget=?, other=?, creator_id=?, creator_name=?, creator_time=?, editor_id=?, editor_name=?, editor_time=? WHERE hall_bidding_id=? AND is_delete=0 
2023-08-12 11:29:42.756 b2b-kaihuile-logback http-nio-5000-exec-177 DEBUG c.a.b.k.m.h.m.H.updateById - ==> Parameters: (String), (String), (String), 2023-07-20 00:00:00.0(Timestamp), 0(Integer), 0(Integer), 44(Integer), 2023-07-19 00:00:00.0(Timestamp), 0(Integer), 无(String), 200(Integer), 祝你新年快乐了(String), cf68f402eef7ca15a29142a8bc944e4f(String), 应俊(String), 2023-07-04 14:47:35.0(Timestamp), cf68f402eef7ca15a29142a8bc944e4f(String), 应俊(String), 2023-08-12 11:29:42.755(Timestamp), 1001(String)
2023-08-12 11:29:42.758 b2b-kaihuile-logback http-nio-5000-exec-177 DEBUG c.a.b.k.m.h.m.H.updateById - <==    Updates: 1
2023-08-12 11:29:42.762 b2b-kaihuile-logback http-nio-5000-exec-165 DEBUG c.a.b.k.m.h.m.H.selectById - ==>  Preparing: SELECT hall_bidding_id,inquiry_detail_id,inquiry_id,corresponding_period,active_time,big_bed_number,double_bed_number,board_number,latest_time,active_type,previously_used_hotel,accommodation_budget,other,is_delete,creator_id,creator_name,creator_time,editor_id,editor_name,editor_time FROM hms_hall_bidding WHERE hall_bidding_id=? AND is_delete=0 
2023-08-12 11:29:42.762 b2b-kaihuile-logback http-nio-5000-exec-165 DEBUG c.a.b.k.m.h.m.H.selectById - ==> Parameters: 1001(String)
2023-08-12 11:29:42.764 b2b-kaihuile-logback http-nio-5000-exec-165 DEBUG c.a.b.k.m.h.m.H.selectById - <==      Total: 1
使用加锁^^设置库存:43
2023-08-12 11:29:42.766 b2b-kaihuile-logback http-nio-5000-exec-165 DEBUG c.a.b.k.m.h.m.H.updateById - ==>  Preparing: UPDATE hms_hall_bidding SET inquiry_detail_id=?, inquiry_id=?, corresponding_period=?, active_time=?, big_bed_number=?, double_bed_number=?, board_number=?, latest_time=?, active_type=?, previously_used_hotel=?, accommodation_budget=?, other=?, creator_id=?, creator_name=?, creator_time=?, editor_id=?, editor_name=?, editor_time=? WHERE hall_bidding_id=? AND is_delete=0 
2023-08-12 11:29:42.767 b2b-kaihuile-logback http-nio-5000-exec-165 DEBUG c.a.b.k.m.h.m.H.updateById - ==> Parameters: (String), (String), (String), 2023-07-20 00:00:00.0(Timestamp), 0(Integer), 0(Integer), 43(Integer), 2023-07-19 00:00:00.0(Timestamp), 0(Integer), 无(String), 200(Integer), 祝你新年快乐了(String), cf68f402eef7ca15a29142a8bc944e4f(String), 应俊(String), 2023-07-04 14:47:35.0(Timestamp), cf68f402eef7ca15a29142a8bc944e4f(String), 应俊(String), 2023-08-12 11:29:42.766(Timestamp), 1001(String)
2023-08-12 11:29:42.769 b2b-kaihuile-logback http-nio-5000-exec-165 DEBUG c.a.b.k.m.h.m.H.updateById - <==    Updates: 1
2023-08-12 11:29:42.773 b2b-kaihuile-logback http-nio-5000-exec-38 DEBUG c.a.b.k.m.h.m.H.selectById - ==>  Preparing: SELECT hall_bidding_id,inquiry_detail_id,inquiry_id,corresponding_period,active_time,big_bed_number,double_bed_number,board_number,latest_time,active_type,previously_used_hotel,accommodation_budget,other,is_delete,creator_id,creator_name,creator_time,editor_id,editor_name,editor_time FROM hms_hall_bidding WHERE hall_bidding_id=? AND is_delete=0 
2023-08-12 11:29:42.773 b2b-kaihuile-logback http-nio-5000-exec-38 DEBUG c.a.b.k.m.h.m.H.selectById - ==> Parameters: 1001(String)
2023-08-12 11:29:42.775 b2b-kaihuile-logback http-nio-5000-exec-38 DEBUG c.a.b.k.m.h.m.H.selectById - <==      Total: 1
使用加锁^^设置库存:42

数据库库存变化结果:初始化50,执行后库存被清空,库存已被抢完

四、总结

  • 使用redisson实现,能够保证多实例下线程安全,代码简单可靠
  • 1
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Redis分布式锁在实际应用中有多种用途。其中之一是解决数据并发竞争的问题。通过使用分布式锁,可以将对某个数据的处理串行化,避免多个客户端同时对同一数据进行操作。另一个应用是防止库存超卖。例如,在一个订单系统中,多个客户端同时下单可能导致库存不足的情况。通过使用分布式锁,可以保证只有一个客户端能够获得锁并进行下单操作,从而避免库存超卖的问题。伪码示例如下: ```java // 加锁并设置有效期 if (redis.lock("RDL", 200)) { // 判断库存 if (orderNum < getCount()) { // 加锁成功,可以下单 order(5); // 释放锁 redis.unlock("RDL"); } } ``` 这段代码中,通过使用分布式锁,只有获得锁的客户端才能执行下单操作,从而保证了订单的顺序性和库存的正确性。除了数据并发竞争和防止库存超卖Redis分布式锁还可以应用于其他需要保证互斥性、同一性、可重入性和容错性的场景。 #### 引用[.reference_title] - *1* *3* [RedisRedisson分布式锁的使用(推荐使用)](https://blog.csdn.net/chuanchengdabing/article/details/121210426)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^koosearch_v1,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [redis分布式锁的应用](https://blog.csdn.net/qq_33803102/article/details/111036517)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^koosearch_v1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

J._.Rong

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值