首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >优惠券超发问题

优惠券超发问题

作者头像
adu
发布于 2022-10-30 06:55:46
发布于 2022-10-30 06:55:46
1.2K00
代码可运行
举报
文章被收录于专栏:adu_blogadu_blog
运行总次数:0
代码可运行

前言

做商城相关的小伙伴经常会有优惠劵的需求,如果没有处理好,很容易导致优惠劵超发,超出领取一系列的问题,影响还是很大的。

测试需求描述

现有一个优惠劵,库存有150张,测试用户领取该优惠劵。

实现过程

1、新建优惠劵表 coupon

2、新建领取优惠劵记录表 user_coupon_records

3、使用springboot+mybatisplus实现需求,这里只展示实现代码,其它相关代码就不做展示了

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Override
@Transactional(rollbackFor = Exception.class)
public Result claim() {
    //获取优惠劵是否有库存
    Coupon coupon = couponMapper.selectOne(new QueryWrapper<Coupon>()
            .eq("id", 1));
    if (coupon.getStock() < 1) {
        throw new MyException("库存不足");
    }
    //减少库存
    int u = couponMapper.inventoryReduction();
    if (u == 1) {
        //添加领取记录
        UserCouponRecords userCouponRecords = new UserCouponRecords();
        userCouponRecords.setUserId(1).setCouponId(1);
        userCouponRecordsMapper.insert(userCouponRecords);
    }
    return ResultUtil.error();
}
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Update("update coupon set stock = stock - 1")
int inventoryReduction();

上面的代码按照我们的逻辑是没有问题,我通过使用 apifox 软件测试也是没有问题,但是如果在高并发下就会出现问题了。

我们通过apifox 软件测试一下多线程下是什么效果。(4个线程)

可以看到库存与领取记录结果,竟然多领取了一张。

问题引发

如果同时来了两个线程(你可以理解成是两个请求),比如先来的那个请求通过了检查(线程 A),这时线程 A 还没有扣减库存,这时线程 B 经过一翻操作也通过了这个检查优惠券是否可领取的方法,然后线程 A 和线程 B 依次扣减库存或者是同时扣减库存。这样就会引发优惠劵超领的情况。

问题解决

| 解决方案 1(Java 代码加锁)

导致这一问题的根本原因是多个线程同时访问这个领取优惠券的方法,那只要保证在同一段只有一个线程进入到这个方法就可以了。

可以将代码这样改 synchronized (this){}

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
synchronized (this) {
    //获取优惠劵是否有库存
    Coupon coupon = couponMapper.selectOne(new QueryWrapper<Coupon>()
            .eq("id", 1));
    if (coupon.getStock() < 1) {
        throw new MyException("库存不足");
    }
    //减少库存
    int u = couponMapper.inventoryReduction();
    if (u == 1) {
        //添加领取记录
        UserCouponRecords userCouponRecords = new UserCouponRecords();
        userCouponRecords.setUserId(1).setCouponId(1);
        userCouponRecordsMapper.insert(userCouponRecords);
    }
    return ResultUtil.error();
}

虽然这样可以解决超发的问题,但是在项目中我们不可以这样写,原因如下:

synchronized 的作用范围是单个 JVM 实例,如果是集群部署系统这里的加锁你可以理解成失效。

在使用了 synchronized 加锁后,就会形成串行等待的问题,当一个线程 A 在领取优惠券方法内执行过久时,其它线程会等待直到线程 A 执行结束。

| 解决方案 2 (SQL层面解决)

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Update("update coupon set stock = stock - 1 where stock > 0")
int inventoryReduction();

发现了吗,只需要将 sql 加个库存判断即可!

MySQL 默认使用的是 InnoDB 引擎,使用 InnoDB 时在修改某一个记录的时候会将这条记录上锁,所以这个修改数据时不会出现多个线程同时修改数据。这样也可以避免优惠券超领。

还有种办法就是乐观锁,可以在表中加个version 字段,每次修改数据的时候这个字段会加 1,也可以直接使用mybatisplus中的乐观锁插件。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Update("update coupon set stock = stock - 1,versioin = version+1 where version=#{上一次的版本号}")
int inventoryReduction();

这里就不演示了,可以自己去试试。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022/07/15 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
公司新来一个同事,把优惠券系统设计的炉火纯青!
如:A优惠券一共发行120张,每一个用户可以领取140张,当一个用户领取优惠券成功的时候,把领取的记录写入到另外一个表中(这张表我们暂且称为表B)
Java团长
2022/12/20
1.7K1
公司新来一个同事,把优惠券系统设计的炉火纯青!
优惠券微服务开发(2)-1024电商平台项目技术选择和创 建聚合工程项目【工业级PaaS云平台+SpringCloudAlibaba+JDK11综合项目实战】
第十三章 电商优惠券微服务业务介绍和模块开发 第1集 互联网公司中优惠券微服务业务介绍和效果体验 简介:介绍常见的优惠券业务和课程案例效果体验 互联网企业最重要的是拉新业务,产品经理 自然诞生了很多玩法 砍价 拼团 裂变 优惠券 电商优惠券逻辑,优惠券的玩法很多,主要讲一下比较常见的优惠券 获取方式维度 被动:新人优惠券 无门槛现金劵 …其他 第一次登录注册某平台,登录成功后进入到首个页面弹出新人红包或者某固定位置领取新人红包,前端领取位置及细节不做详细讲解,根据实际业务场景而定 主动:领取优惠券
高大北
2022/09/16
1.2K0
优惠券微服务开发(2)-1024电商平台项目技术选择和创 建聚合工程项目【工业级PaaS云平台+SpringCloudAlibaba+JDK11综合项目实战】
【 Redis | 实战篇 秒杀实现 】
实现全局ID生成器,秒杀优惠券(基于乐观锁解决超卖问题),秒杀的一人一单(单机与集群线程安全问题)
张哈大
2025/05/31
1780
【 Redis | 实战篇 秒杀实现 】
Redis实战11-实现优惠券秒杀下单
1:查下优惠券、2:判断是否秒杀开始;3:判断秒杀是否结束;4:判断库存是否充足;5:扣减库存;6:创建订单;
凯哥Java
2023/02/11
1.2K0
Redis实战11-实现优惠券秒杀下单
Redis解决秒杀下单
上述就是实现最基本的优惠卷下单功能。当然真实的业务场景绝对不会是向我们这么简单的。
用户11097514
2024/05/30
2480
Redis解决秒杀下单
万级TPS优惠券系统设计与实践
优惠券系统主要涵盖四个核心能力:创建、派发、使用、统计。本篇主要针对派发这部分,在系统设计和落地过程中遇到和解决的一些问题做一个简单记录,以便后来补缺。
腾讯云开发者
2024/11/13
3.6K0
万级TPS优惠券系统设计与实践
大厂的优惠券系统是如何设计的?
如商家创建了一批优惠券,共1000张,使用时间为2022-11-11 00:00:00 ~ 2022-11-11 23:59:59,规定只有数码类目商品才能使用,满100减50。
JavaEdge
2022/05/10
10K2
大厂的优惠券系统是如何设计的?
Redis实战12-优惠券实现一人一单功能
在上一篇, Redis实战11-实现优惠券秒杀下单 我们已经把超卖问题解决了。接下来,我们来开发,优惠券一人一单功能。通过本文学习,您将有如下收获:
凯哥Java
2023/02/18
1.1K0
Redis实战12-优惠券实现一人一单功能
电商优惠券simple
create table t_coupon ( coupon_id int null comment '券ID,主键',
用户7635214
2022/08/20
6390
vivo 全球商城:优惠券系统架构设计与实践
优惠券是电商常见的营销手段,具有灵活的特点,既可以作为促销活动的载体,也是重要的引流入口。优惠券系统是vivo商城营销模块中一个重要组成部分,早在15年vivo商城还是单体应用时,优惠券就是其中核心模块之一。随着商城的发展及用户量的提升,优惠券做了服务拆分,成立了独立的优惠券系统,提供通用的优惠券服务。目前,优惠券系统覆盖了优惠券的4个核心要点:创、发、用、计。
2020labs小助手
2021/08/09
1.8K1
【📕分布式锁通关指南 01】从解决库存超卖开始加锁的初体验
背景非常简单,就是在电商项目中,用户购买商品和数量后后,系统会对商品的库存进行相应数量的扣减。因此,我们模拟这个场景就需要商品表和库存表两张表,但业务并不是这里的重点,需要简化一下,一张简单的商品库存表足以,如下:
别惹CC
2025/01/15
3750
【📕分布式锁通关指南 01】从解决库存超卖开始加锁的初体验
优惠券系统设计
对于一个电商系统,一般都会有很多的促销手段,包括优惠券,拼团,砍价,老带新等等。我们在线教育的产品(腾讯课堂,企鹅辅导等)作为一个电商系统(商品比较单一,主要是卖课),自然也少不了会接入这些促销系统来提升我们的活跃用户与流水,就腾讯课堂而言,优惠券是众多促销手段中使用频次最高,优惠金额最多的一种手段了。
榴莲其实还可以
2020/06/11
5.4K0
优惠券系统设计
阿里大数据竞赛第一名大神github源代码分享(O2O优惠券使用预测)
队伍简介 队伍名 “诗人都藏在水底”,三位队员分别是来自北大的wepon和charles,来自中科大的云泛天音 赛题介绍 本赛题提供用户在2016年1月1日至2016年6月30日之间真实线上线下消费行为,预测用户在2016年7月领取优惠券后15天以内是否核销。评测指标采用AUC,先对每个优惠券单独计算核销预测的AUC值,再对所有优惠券的AUC值求平均作为最终的评价标准。 解决方案 本赛题提供了用户线下消费和优惠券领取核销行为的纪录表,用户线上点击/消费和优惠券领取核销行为的纪录表,记录的时间区间是2
机器学习AI算法工程
2018/03/15
1.9K0
阿里大数据竞赛第一名大神github源代码分享(O2O优惠券使用预测)
springcloudAlibaba&rancher【后端专题】
DevOps即Development和Operations的组合词,是一组过程、方法与系统的统称,用于促进开发应用程序或软件工程、技术运营和质量保障QA部门之间的沟通、协作与整合。
高大北
2022/12/20
2.6K0
springcloudAlibaba&rancher【后端专题】
营销模块数据库表解析:优惠券功能
本文主要对优惠券功能相关表进行解析,采用数据库表与功能对照的形式。 相关表结构 优惠券表 用于存储优惠券信息,需要注意的是优惠券的使用类型:0->全场通用;1->指定分类;2->指定商品,不同使用类型的优惠券使用范围不一样。 create table sms_coupon ( id bigint not null auto_increment, type int(1) comment '优惠卷类型;0->全场赠券;1->会员赠券
macrozheng
2019/08/13
3.1K0
营销模块数据库表解析:优惠券功能
订单服务以及优惠券服务及rabbitmq(7)-1024电商平台项目技术选择和创 建聚合工程项目【工业级PaaS云平台+SpringCloudAlibaba+JDK11综合项目实战】
第二十七章 新版消息队列RabbitMQ回顾和容器化安装部署 第1集 基于Linux服务器安装RabbitMQ容器化部署 简介:Docker安装RabbitMQ消息队列 阿里云安装RabbitMQ 最少 2核4g或者推荐 2核8g(用家人账号购买,接近1折,初次买1年或者3年) 登录个人的Linux服务器 ssh root@8.129.113.233 Docker安装RabbitMQ 地址:https://hub.docker.com/_/rabbitmq/ #拉取镜像 docker pull ra
高大北
2022/09/16
1.7K0
订单服务以及优惠券服务及rabbitmq(7)-1024电商平台项目技术选择和创 建聚合工程项目【工业级PaaS云平台+SpringCloudAlibaba+JDK11综合项目实战】
SpringBoot实现并发、超发和锁机制/抢购示例:超发、乐观锁、悲观锁和Redis的使用
上述的超发现象,归根到底在于数据库时被多个线程同时访问的,在没有加锁的情况下,上述代码并不是线程安全的。
用户10175992
2022/11/15
1.2K0
SpringBoot实现并发、超发和锁机制/抢购示例:超发、乐观锁、悲观锁和Redis的使用
MySQL数据库基础练习系列45、优惠券发放系统
很多学生或者说是初学者在学习完成数据库的基础增删改查后就自认为在数据库这里就很熟悉了,但是不接触项目根本部知道需求,我这里准备了50个项目的基本需求来让大家来熟练各类项目的列信息,让大家更好的深入项目进行实战式的练习,可以让大家在后面面试的时候有更多更丰富的资历让大家可以与面试官侃侃而谈。
红目香薰
2024/06/16
2860
MySQL数据库基础练习系列45、优惠券发放系统
Redis进阶学习03---Redis完成秒杀和Redis分布式锁的应用
数据库自增指的是单独使用数据库中某一张表来专门存放主键,当我们需要的时候,只需要提前从该表中读取出一批主键集合,缓存在内存中即可,但是该方法显然太慢了,因此不推荐使用
大忽悠爱学习
2022/05/09
8610
Redis进阶学习03---Redis完成秒杀和Redis分布式锁的应用
以超卖为例✨各种场景下如何防止并发污染数据?
比如:商品库存扣减、用户余额调整、火车票、机票、演唱会入场票的扣减(类似商品库存扣减)等...
菜菜的后端私房菜
2024/08/13
3551
推荐阅读
相关推荐
公司新来一个同事,把优惠券系统设计的炉火纯青!
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档