黑马点评day03优惠券秒杀(超卖问题)

文章讨论了在高并发环境下如何设计全局唯一ID生成器,以及在秒杀场景中如何处理库存超卖问题。提出了使用时间戳和序列号组合生成ID,并利用Redis进行分布式计数。针对超卖问题,文章探讨了乐观锁(version法和CAS法)的应用,并指出在高并发下可能导致的失败情况。最后,文章提出了解决一人一单问题的策略,包括使用悲观锁确保线程安全,但在分布式环境中仍存在的挑战。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

总览:

1、全局ID生成器

观察到未使用AUTO_INCRE

当用户抢购时,就会生成订单并保存到tb_voucher_order这张表中,而订单表如果使用数据库自增ID就存在一些问题:

* id的规律性太明显
* 受单表数据量的限制

场景分析:如果我们的id具有太明显的规则,用户或者说商业对手很容易猜测出来我们的一些敏感信息,比如商城在一天时间内,卖出了多少单,这明显不合适。

场景分析二:随着我们商城规模越来越大,mysql的单表的容量不宜超过500W,数据量过大之后,我们要进行拆库拆表,但拆分表了之后,他们从逻辑上讲他们是同一张表,所以他们的id是不能一样的, 于是乎我们需要保证id的唯一性。

为了增加ID的安全性,我们可以不直接使用Redis自增的数值,而是拼接一些其它信息:
ID:long型,8字节,64bit
ID的组成部分:符号位:1bit,永远为0,正数 
时间戳:31bit,以秒为单位,可以使用69年
序列号:32bit,秒内的计数器,支持每秒产生2^32个不同ID

RedisWorker.java:

/**     
* 由正常年月日(20220101)转换为时间戳     
*/    
public Long makeTime(){
        LocalDateTime now = LocalDateTime.of(2022, 1, 1, 0, 0, 0);        
        long second=now.toEpochSecond(ZoneOffset.UTC);        
        return second;    
        }
/**     
* 开始时间戳     
*/    
    private static final long BEGIN_TIMESTAMP = 1640995200L;    
/**     
* 序列号的位数     
*/    
    private static final int COUNT_BITS = 32;    
    @Autowired    
    private RedisUtil redisUtil;    
public long nextId(String keyPrefix) {
// 1.生成时间戳        
    LocalDateTime now = LocalDateTime.now();        
    long nowSecond = now.toEpochSecond(ZoneOffset.UTC);        
    long timestamp = nowSecond - BEGIN_TIMESTAMP;        
// 2.生成序列号        
// 2.1.获取当前日期,精确到天        
    String date = now.format(DateTimeFormatter.ofPattern("yyyy:MM:dd"));        
// 2.2.redis中自增长记录总数量(条)        
    long count=redisUtil.incr("icr:" + keyPrefix + ":" + date,1);        
// 3.拼接并返回生成的ID        
    return timestamp << COUNT_BITS | count;    
}
}

2、实现优惠券秒杀下单

2.1代码实现

流程:

voucherOrderServiceImpl.java:

@Servicepublic 
class VoucherOrderServiceImpl extends ServiceImpl<VoucherOrderMapper, VoucherOrder> implements IVoucherOrderService {

    @Autowired    
    private ISeckillVoucherService seckillVoucherService; 
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值