优惠券兑换码生成需求——批量生成任务全局限制唯一

前段时间收到一个优惠券兑换码的需求:管理后台针对一个优惠券发起批量生成兑换码,这些兑换码可以导出分发到各个合作渠道(比如:抖音、京东等),用户通过这些渠道获取到兑换码之后,再登录到我司研发的商城,使用兑换码兑换获得对应的优惠券。

整个需求大致分为两个部分:(1)批量生成兑换码;(2)使用兑换码兑换优惠券。接下来的几篇文章将针对批量生成兑换码功能实现过程中碰到的一系列问题进行分析描述,以便读者再碰到类似问题,可以快速解决。

文章系列如下:

《事务失效问题分析》

《事务同步回调问题分析》

《批量生成任务全局限制唯一》

在此之前,先简单介绍商城技术架构:商城后端服务均采用SpringCloud框架开发,数据库主备,商城所有服务共用一个数据库,数据库持久化框架为MybatisPlus,所有服务采用K8s技术进行部署和治理。


一、问题描述

在《事务同步回调问题》一文末尾,笔者抛出了一个问题:由于兑换码生成过程比较占用资源,所以全平台保证同时只能有一个生成任务在执行。根据生成业务流程图如何保证插入兑换生成记录的并发安全?

二、问题分析

根据上述流程图可知,如果两个用户同时对两个优惠券发起兑换码生成请求,按照通常编码方式,可能会出现两个任务同时执行的情况。通常编码编码方式如下:

java 复制代码
if(dhCodeService.listDoingStatus().size() > 0) {
    dbCodeBatchService.insert(dbCodeBatch);    
}

上述代码存在线程安全问题,有读者可能会建议这段代码加一个synchronized即可,但大家不要忘了,咱们的系统是分布式系统,多服务实例,synchronized只能解决单进程(非分布式)场景中的并发问题。

针对上述问题,有以下解决方案:

(1)分布式锁:如果公司有久经考验相当靠谱的分布式锁方案,并且公司有非常熟悉分布式锁使用的老司机,否则一旦在并发场景出现问题,很难分析并发问题出现的原因;

(2)数据库行级锁:由于我司电商平台只有一个数据库,所以可以放心使用该方案。行级锁有两种使用方式:

    • select * for update:查询时使用for update可以锁住对应的数据行
    • 更新时直接使用条件语句,如果条件满足则更新

笔者将使用条件更新的方式来保证兑换码执行中记录的唯一性,从而保证兑换码生成任务的唯一性。

三、解决方案

具体方案:编写一条根据条件进行插入的sql语句,如下:

sql 复制代码
# 兑换码记录表dh_code_batch中如果不存在状态为DOING的记录,则写入一条生成记录(状态为DOING)
<insert id="saveIfNotExistDoing" parameterType="com.xxx.DhCodeBatch">
    INSERT INTO dh_code_batch (`coupon_id`, `num`, `status`)
    SELECT #{batch.couponId}, #{batch.num}, 'DOING' FROM DUAL
    WHERE NOT EXISTS (SELECT id FROM dh_code_batch WHERE `status` = 'DOING');
</insert>

那么check()方法中对执行中任务记录的唯一校验代码如下:

java 复制代码
if(!dhCodeBatchService.saveIfNotExistDoing(dhCodeBatch)) throw new BusinessException("当前有兑换码生成任务正在执行,请稍后再试!");

至此,兑换码生成记录写入并发问题已解决,兑换码生成任务全局串行得到保证。感谢大家的持续关注!

附带兑换码生成工具类下载

相关推荐
qq_39280795几秒前
Qt 注册 C++ 给 QML 调用的几种方式
数据库·c++·qt
程序员夏末2 分钟前
【MySQL | 第二篇】 MVCC的底层实现(多版本并发控制)
数据库·sql·mysql
庞轩px3 分钟前
线程池核心参数与拒绝策略深度解析
java·jvm·数据库
油丶酸萝卜别吃4 分钟前
MySQL 事务机制深度解析:从 ACID 到底层实现
数据库·mysql
xcLeigh7 分钟前
Oracle 迁移深度复盘:多数据库选型决策全解析
大数据·数据库·sql·oracle·数据迁移·数据管理
guestsun8 分钟前
Idea反编译插件--方便查看和修改class文件
java·intellij-idea·jar·反编辑工具·idea反编译插件·class反编译·jar反编译
工边页字8 分钟前
图文教学,服务端如何发送(钉钉 +飞书 )机器人通知
java·前端·后端
王仲肖13 分钟前
PostgreSQL pageinspect 插件深度解析
数据库·postgresql
云边有个稻草人15 分钟前
【MySQL】第十四节—事务:从基础概念到隔离性理论与实践 | 详解
数据库·mysql·事务·隔离级别·事务的隔离性·事务提交方式