0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

电商平台通用取货码设计

jf_ro2CN3Fa 来源:vivo互联网技术 2023-01-05 10:30 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

一、背景

随着O2O线上线下业务的不断扩展,电商平台也在逐步完善交易侧相关的产品功能。在最近的需求版本中,业务方为进一步提升用户的使用体验,规划了取货码生成及订单核销相关逻辑,目的是让线上的用户在付完款之后能够到店取货或者安排导购派送。

日常生活中,我们对取货码、核销这类功能使用的经历大部分都来自:看电影前取票、吃饭后出示券码、快递柜取包裹等等,它们都有一些类似的特点,比如:

  • 取货码长度相对较短,比起动辄十几二十位订单号,几位的数字码更方便记忆和输入;
  • 除了数字取货码,还提供二维码,方便终端进行扫描并核销。

取货码使用起很简单,然而像“冰山”一样,隐藏在简单外表下面却需要严谨的设计和细致的逻辑,可以说麻雀虽小五脏俱全。本文介绍的设计也比较有趣,而且按此思路可以实现市面上大多数核销类券码的生成,同时也能满足业务的SaaS化,算是一个相对通用的能力,在此把整个设计分享给大家。

基于 Spring Boot + MyBatis Plus + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能

  • 项目地址:https://github.com/YunaiV/ruoyi-vue-pro
  • 视频教程:https://doc.iocoder.cn/video/

二、简单系统的单表业务

如果业务的体量不大,店铺流量比较小,未形成平台的规模,比如给个体经营者使用的系统。那么取货码或券码的实现就比较简单,跟订单共享一张大横表或者使用扩展表跟订单进行关联就行了,这个阶段也无需做过度设计。

表的设计如下图:

86abd1ae-8c63-11ed-bfe3-dac502259ad0.jpg

不过需要注意的是一般订单号都是比较长的,通常都在十几二十位(当然也有比较短的订单号,如果订单号比较短,取货码也可采用订单号)我们假设订单号18位,取货码8位,即订单号的取值范围远大于取货码,那么在订单号的生命周期内,取货码是有很大几率存在重复的。解决起来相对简单,我们只需要保证在任意条件下,未核销 状态的数字码不重复即可,也即已核销的数字码可以回收利用。

那么取货码的生成逻辑就很清晰了,下面用伪代码模拟真实的实现逻辑:

伪代码实现

for(;;){
step1获取随机码:Stringcode=this.getRandomCode();
step2执行SQL:SELECTCOUNT(1)FROMorder_mainWHEREcode=${code}ANDwrite_off_status=0;
step3判断是否可以插入:if(count>0){continue;}
step4执行数据写入:UPDATEorder_mainSETcode=${code},qr_code=${qrCode},write_off_status=0WHEREorder_no=${orderNo}
}

注意: 这里step2和step4不是原子操作,存在并发问题,实际应用中最好使用分布式锁,把操作锁住。

基于 Spring Cloud Alibaba + Gateway + Nacos + RocketMQ + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能

  • 项目地址:https://github.com/YunaiV/yudao-cloud
  • 视频教程:https://doc.iocoder.cn/video/

三、 复杂平台的分库分表业务

通过简单的单表设计,我们能管窥一斑,了解取货码大致的实现逻辑。不过我们在把简单方案往大型项目上进行落地的时候,就需要考虑很多方面,设计也需要更精巧。SaaS化的电商平台会比简单的单表业务复杂很多,重点体现在:

  1. SaaS 产品涉及的店铺很多且订单量大,需要设计大容量存储,所以订单表基本使用分库分表,显然作为订单附属的取货码表也得使用相同的策略;
  2. B端和C端用户的体验非常重要,服务端接口的设计需要充分考虑鲁棒性,完善最基本的重试及容错能力;
  3. 不同业务方对于取货码的要求可能不太一样,取货码的设计需要具有通用性以及个性化的配置属性。

3.1 详细设计

取货码表的设计推荐使用和订单一致的分库分表策略,好处是:

  1. 和订单一样,支撑海量订单行的存储;
  2. 方便利用同样的分库分表因子进行查询(例如:open_id、member_id)。

在考虑落地实现上,我们遇到了第一个讨论的点,那就是取货码是做到“门店唯一 ”还是“全局唯一 ”?

3.2 门店唯一方案

刚开始考虑使用类似饭馆取餐码类似的逻辑,保证取货码在各自门店保持唯一就行了。类似如下图交互,图中用户A和用户B持有相同的取货码,用户A、B分别去他们对应的店铺完成核销,整个交易过程就结束了。但是这得保证用户A和B能正确地在各自订单归属的店铺完成核销,显然这个方案是带有风险的!

86b473ae-8c63-11ed-bfe3-dac502259ad0.jpg

下图所示的这种情况下,用户A、B也能正常核销,不过串单了,原本属于用户A的订单被用户B核销了。这种问题出现的本质原因在于纯粹的数字码无法带有用户的标识,虽然可以在核销前做人为的核验身份来避免,但依然属于高风险的系统设计,所以门店唯一方案不可取!

86be589c-8c63-11ed-bfe3-dac502259ad0.jpg

3.3 全局唯一方案

全局唯一方案风险小,但实现难度稍高一点。核心问题在于如何判定随机生成的取货码是全局唯一的,当然如果系统本身依赖ES这类存储介质,可以在插入前先查询ES,不过查询和写入ES对于实时性接口来说稍微有点重,没有直接查库表来得直接。假设某业务方分成了4个库4张表,总计16表,取货码的长度确定为8位,那如何在多库多表的Mysql中查询并保证全局唯一呢?遍历表的方式肯定不可取!

86c6d7a6-8c63-11ed-bfe3-dac502259ad0.jpg

为解决上述的疑问,我们在设计的时候可以在取货码的编排上做点文章,如下步骤做具体详解:

步骤①: 可以将8位的取货码分成两个区域,“随机码区域”+“库表位置” ,下图示例:

86cdc854-8c63-11ed-bfe3-dac502259ad0.jpg

步骤②: 随机码区域暂不介绍,我们来看下2位库表如何映射到4库4表组成的16张表中。

这里也有两套方案:

【方案一】 可以选择2位库表的首位作为库编号,末位作为表编号。好处是映射较为简单,但是容量不够大,如果分的库或表>9,扩展就会有点麻烦。如下图,我们把末尾“12”逻辑映射到了“1库的编号为2的表”;

86d34018-8c63-11ed-bfe3-dac502259ad0.jpg

【方案二】 将4库4表二维结构转成一维,以0为初始值进行递增,(0库, 0表) → 00, (0库, 1表) → 01... , (3库, 3表) → 15。好处是容量变大了,最大支持99张表,不受库或表单一条件的限制,缺点就是映射逻辑写起来麻烦点,不过这不是问题。

86dc3466-8c63-11ed-bfe3-dac502259ad0.jpg

取货码经过简单编排,我们完成了取货码的到库表的映射逻辑,解决了取货码存取的问题。其实仔细想想,关于全局唯一的问题其实也解决掉了,我们只要保证前6位随机码 在单表里保证唯一即可,理论上支持单表在未核销状态下范围为:000000 ~ 999999条记录,容量是足够的。关键我们把多库多表的查询就简化成了只跑一个SQL,效率大大提升。

3.4 方案落地遇到的问题

既然本篇是介绍SaaS化的完整方案,在落地的时候或多或少会遇到一些问题,这边介绍三个实际遇到的典型问题,并给出一些解决方案:

【问题一】 使用Math.random()生成的6位随机码和表里的重复了,如何处理?

【解决】 其实重复的情况有两种:

  1. 可能是表里已经存在数字相同未核销的取货码;
  2. 另外一种情况就是别的事务在正在操作,正好有个分布式事务锁住了一样的数字码(概率很低,但是是有可能的)。

这两种情况的出现就需要我们进行优雅地重试了!大致思路如下伪代码:

//step1根据分库分表因子获取库表编号,userCode-用户编号、tenantId-租户编号
Stringsuffix=getCodeSuffix(userCode,tenantId);

//step2批量获取6位随机码
for(inti=1;i<=5;i++){
//批量获取随机数。每次重试,取2的指数级量进行过滤,相比暴力执行for循环,这种方式能减少和DB的交互
ListtempCodes=getRandomCodes(2<< i);
   //过滤掉分布式锁
filterDistributeLock(tempCodes);
//过滤掉数据库存在的随机码
filterExistsCodes(tempCodes);
returntempCodes;
}

//step3处理随机码,随机码入库
for(Stringcode:codes){
//加锁,判断加锁是否成功。推荐使用Redis分布式锁
booleanhasLockd=isLocked(code);
try{
//执行入库
insert(object);
}finally{
//解锁
}
}

//step4执行后置二维码图片等逻辑

【注意】

  1. 推荐使用指数级重试的方式(2 << i),逐次递增random的数量,减少和DB的交互;
  2. 建议数字码生成完毕后加锁并执行INSERT,生成图片地址等耗时严重的动作可以后置UPDATE上去。

【问题二】 项目中使用了分库分表的组件(比如:ShardingSphere-JDBC),怎么动态修改数据源?也就是同时支持分库分表因子(比如:member_id、open_id等)以及根据取货码计算的库表动态查询。

【解决】 我们以ShardingSphere-JDBC作为为案例来给出一些配置及伪代码,具体可以参考:《强制路由::ShardingSphere》,其他开源的分库分表组件或者自研产品不做赘述,可以自己手动写个插件,别怕,即使再难,也要相信有光!

配置及伪代码

//ShardingSphere-JDBC依赖的配置文件jdbc-sharding.yaml
...
shardingRule:
tables:
...
#取货码表
order_code:
actualDataNodes:DS00$->{0..3}.order_pick_up_0$->{0..3}
#配置库的计算逻辑
databaseStrategy:
hint:
algorithmClassName:com.xxx.xxxxx.xxx.service.impl.DbHintShardingAlgorithm
#配偶之表的计算逻辑
tableStrategy:
hint:
algorithmClassName:com.xxx.xxxxx.xxx.service.impl.DbHintShardingAlgorithm
...

//java代码
try(HintManagerhintManager=HintManager.getInstance()){
hintManager.addDatabaseShardingValue("order_code"/**取货码表*/,DbHintShardingAlgorithm.calDbShardingValue(tenantId,code));
hintManager.addTableShardingValue("order_code"/**取货码表*/,DbHintShardingAlgorithm.calTabShardingValue(tenantId,code));

Objectxxx=xxxMapper.selectOne(queryDTO);
}

【注意】

  1. 这里介绍一种编程式的解决方案,好处是配置简单、比较灵活,缺点就是代码稍微多一点。其实ShardingSphere还支持注解的方式,可以自己研究下;
  2. 第一条说了比较灵活,体现在自己实现的 “DbHintShardingAlgorithm.calDbShardingValue(tenantId, code)” 方法上,这个方法可以自己定义,所以我们的入参可以是通用的分库分表因子,也可以是自定义的取货码的“库表位置”字段,非常灵活。

【问题三】 如何做到更强的扩展性,适用SaaS平台以及不同的业务场景?

【解决】 细心的小伙伴应该注意到了 "tenantId" 这个字段,这是个租户的编码,在实际编码会进行透传。我们可以利用这个字段针对不同的租户(或叫业务方)来做不同的配置,比如:取货码的长度、取货码编排的方式、取货码映射库表位置的策略等等做成可配,只要把主干逻辑进一步抽象,并使用策略模式进行个性化编码。

四、总结

实现取货码逻辑的时候,发现网上券码这块的方案、技术文章比较少,当时萌生了写篇文章抛砖引玉做个分享的想法。事实上,我相信大多数公司可能或多或少也是这么做的,哪怕采取了别的方案也能殊途同归。本篇文章整体只是介绍了一个思路,而这个思路类似一个简化版的订单分库分表,但这就是神奇所在,事实上我们还可以将一些常用的技术方案落地到不同的应用场景,大胆地做一些尝试,多走一些未曾设想过的道路!



审核编辑 :李倩


声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 代码
    +关注

    关注

    30

    文章

    4942

    浏览量

    73168
  • 电商
    +关注

    关注

    1

    文章

    470

    浏览量

    29800

原文标题:电商平台通用取货码设计

文章出处:【微信号:芋道源码,微信公众号:芋道源码】欢迎添加关注!文章转载请注明出处。

收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    亚马逊平台 API:解锁潜能的技术钥匙

    ​ 亚马逊作为全球领先的平台,其庞大的生态系统为开发者提供了丰富的编程接口(API)。这些 API 是开发者与亚马逊平台进行数据交互、实现自动化操作的核心工具。理解并合理运用这些
    的头像 发表于 11-24 15:39 174次阅读
    亚马逊<b class='flag-5'>平台</b> API:解锁<b class='flag-5'>电</b><b class='flag-5'>商</b>潜能的技术钥匙

    API接口开放平台的生态构建与运营策略

    ​ 在当今数字化商业环境中,API接口开放平台已成为连接商家、开发者和终端用户的核心枢纽。通过提供标准化的接口,平台赋能第三方快速集成
    的头像 发表于 10-28 16:40 609次阅读
    <b class='flag-5'>电</b><b class='flag-5'>商</b>API接口开放<b class='flag-5'>平台</b>的生态构建与运营策略

    API是什么?常用的API有哪些?发挥着怎样的作用?

    Interface)是软件系统之间通信的桥梁,它定义了如何请求和交换数据。API特指在电子商务领域中,用于连接电平台、支付系统、物
    的头像 发表于 10-28 16:35 426次阅读
    <b class='flag-5'>电</b><b class='flag-5'>商</b>API是什么?常用的<b class='flag-5'>电</b><b class='flag-5'>商</b>API有哪些?发挥着怎样的作用?

    平台要的质检报告是什么

    如果您在京东、天猫、拼多多、亚马逊等平台上进行产品销售,平台通常会要求提供“质检报告”。这个报告实际上是由具有CMA或CNAS资质的实验室出具的产品检测报告。下面为您详细说明质检报
    的头像 发表于 10-20 17:10 526次阅读
    <b class='flag-5'>电</b><b class='flag-5'>商</b><b class='flag-5'>平台</b>要的质检报告是什么

    小红书 API 开启小红书店铺内容营销新范式

    ​ 在当今数字化浪潮中,平台不断寻求创新以提升用户体验和商业效率。小红书作为中国领先的社交电平台,凭借其独特的社区生态和内容驱动模式,
    的头像 发表于 08-28 16:00 452次阅读
    小红书<b class='flag-5'>电</b><b class='flag-5'>商</b> API 开启小红书店铺<b class='flag-5'>电</b><b class='flag-5'>商</b>内容营销新范式

    小红书 API 助力,小红书平台笔记营销效果量化

    ​ 在当今数字化营销时代,小红书作为领先的社交电平台,用户通过分享“笔记”内容推动产品销售。然而,营销效果的量化常面临数据碎片化、指标模糊等挑战。本文将探讨如何利用小红书 API
    的头像 发表于 08-27 15:26 489次阅读
    小红书<b class='flag-5'>电</b><b class='flag-5'>商</b> API 助力,小红书<b class='flag-5'>平台</b>电<b class='flag-5'>商</b>笔记营销效果量化

    抖音 API 接口:抖音平台活动热度实时监测

    ​ 抖音作为全球领先的短视频平台,其商业务近年来蓬勃发展,吸引了众多商家和消费者。实时监测活动热度,对于商家优化营销策略、平台提升用户
    的头像 发表于 08-21 15:30 570次阅读
    抖音<b class='flag-5'>电</b><b class='flag-5'>商</b> API 接口:抖音<b class='flag-5'>平台</b>电<b class='flag-5'>商</b>活动热度实时监测

    API 开启多平台营销推广数据整合新玩法

    ​  在当今数字化时代,商行业竞争日益激烈,企业往往需要在多个平台(如淘宝、京东、抖音等)同时开展营销推广活动。然而,这些平台数据分散、格式不一,导致营销决策效率低下。
    的头像 发表于 08-12 14:19 636次阅读
    <b class='flag-5'>电</b><b class='flag-5'>商</b> API 开启多<b class='flag-5'>平台</b>营销推广数据整合新玩法

    API 接口:多平台商品评论分析的利器

    ​ 在当今竞争激烈的环境中,商品评论是消费者决策的关键参考。然而,手动收集和分析多个平台(如淘宝、京东、拼多多等)的评论数据耗时耗力,且容易出错。
    的头像 发表于 08-11 14:53 691次阅读
    <b class='flag-5'>电</b><b class='flag-5'>商</b> API 接口:多<b class='flag-5'>平台</b>商品评论分析的利器

    借助 API,多平台客户评价一键抓取

    ​  在当今竞争激烈的环境中,客户评价是影响消费者决策的关键因素。商家需要从多个平台(如 Amazon、eBay、淘宝等)实时抓取和分析这些评价,以优化产品和服务。然而,手动收集耗时费力,且容易
    的头像 发表于 08-11 14:49 587次阅读

    API 赋能,多平台促销活动精准同步

    ​ 在当今竞争激烈的环境中,商家经常需要在多个平台(如淘宝、京东、亚马逊等)同时开展促销活动。然而,手动管理这些活动不仅耗时费力,还容易出错,导致价格不一致、库存超卖或活动时间冲突等问题。
    的头像 发表于 08-11 14:40 517次阅读
    <b class='flag-5'>电</b><b class='flag-5'>商</b> API 赋能,多<b class='flag-5'>平台</b>促销活动精准同步

    API驱动的大型平台库存优化

    ​ 在当今电子商务的快速发展中,大型平台(如淘宝、京东或Amazon)面临着巨大的库存管理挑战:库存过剩会增加存储成本,库存不足则导致销售损失。API(应用程序编程接口)作为一种核心技术,通过
    的头像 发表于 07-15 14:42 380次阅读
    API驱动的大型<b class='flag-5'>电</b><b class='flag-5'>商</b><b class='flag-5'>平台</b>库存优化

    抖音 API 接口和传统接口,直播数据处理谁更快?

    ​ 在直播蓬勃发展的今天,数据处理速度成为平台竞争力的关键。抖音作为新兴力量,其API接口针对直播场景进行了优化,而传统
    的头像 发表于 07-09 15:39 438次阅读
    抖音<b class='flag-5'>电</b><b class='flag-5'>商</b> API 接口和传统<b class='flag-5'>电</b><b class='flag-5'>商</b>接口,直播数据处理谁更快?

    淘宝 API 接口 VS 其他平台,优势究竟在哪?

    ​ 在当今数字化时代,API(应用程序编程接口)已成为企业整合平台功能、提升运营效率的关键工具。淘宝作为中国最大的
    的头像 发表于 07-09 15:11 421次阅读
    淘宝<b class='flag-5'>电</b><b class='flag-5'>商</b> API 接口 VS 其他<b class='flag-5'>平台</b>,优势究竟在哪?

    京东 API 接口,订单管理高效解决方案!

    ​ 在当今高速发展的时代,京东作为领先的平台,其 API 接口为商家和开发者提供了强大的工具,帮助实现订单管理的高效化。本文将逐步解
    的头像 发表于 07-04 16:12 563次阅读
    京东<b class='flag-5'>电</b><b class='flag-5'>商</b> API 接口,订单管理高效解决方案!