导读(3行收益):卖卡密、充值码、激活码这类虚拟商品,最容易踩三个坑:卡密被重复用、支付成功没发货、退款了还能核销。本文给一套虚拟商品自动发货做法:卡密生成、核销加锁、异常退款与对账,附关键 SQL。看完虚拟商品不再扯皮。
一、虚拟商品为什么总出事
三个高发事故:
- 卡密重复用:同一码被两个用户各核销一次;
- 支付成功没发货:回调丢了,用户来投诉;
- 退款后还能用:钱退了,卡密照样能激活。
根源是发货与核销没有加锁,也没有和退款状态联动。
二、卡密怎么生成
- 每个 SKU 预生成一批卡密(加密随机串,含校验位);
- 卡密绑定 SKU、批次、状态(未售/已售/已核销/已作废);
- 下单时按 FIFO 锁定一张未售卡密,状态转已售。
避坑:卡密太短可猜——被批量枚举;下单时才现生成——并发下单会撞码;卡密明文存库——拖库即泄露。
三、自动发货怎么触发
支付成功 -> 锁定卡密 -> 推送用户 -> 记录发货日志
支付失败/超时 -> 释放卡密回未售池
- 支付回调成功后自动发码;
- 回调丢失时,定时任务轮询补发货;
- 发货记录带订单号、卡密批次、时间。
避坑:只靠回调发货——回调丢了就永远不发;发货无日志——出问题查不到;发货失败不重试——用户干等。
四、核销怎么防重复
UPDATE `card_secret`
SET `status` = 2
WHERE `id` = ? AND `status` = 1
- 核销用条件更新(CAS),命中行数为 0 说明已被核销;
- 核销记录带时间、来源、用户;
- 已核销卡密再次请求直接拒绝,不报错泄露信息。
避坑:先查再更新——并发下两个请求都查到未核销;核销不幂等——重试一次就多发;核销无日志——事后对不上。
五、异常退款怎么处理
- 退款成功后,对应卡密状态转「已作废」;
- 已核销的卡密退款需人工审核(钱已花出去);
- 作废后再请求核销直接拒绝。
避坑:退款不联动卡密——钱退了码还能用;已核销也自动退——资损;作废码继续可用——黑产套利。
六、数据表怎么设计
CREATE TABLE `card_secret` (
`id` BIGINT PRIMARY KEY AUTO_INCREMENT,
`sku_id` BIGINT,
`batch_no` VARCHAR(32),
`secret_code` VARCHAR(64),
`status` TINYINT DEFAULT 0, -- 0未售 1已售 2已核销 3已作废
`order_id` BIGINT,
`sold_at` DATETIME,
`used_at` DATETIME,
`created_at` DATETIME
) COMMENT='卡密表';
关键点:状态单向流转不可逆;核销用条件更新加锁;退款联动作废。避坑:状态可随意改——重复核销;secret_code 明文——泄露风险。
七、踩坑清单
- [ ] 卡密太短可猜;
- [ ] 下单时才现生成;
- [ ] 只靠回调发货;
- [ ] 先查再更新核销;
- [ ] 核销不幂等;
- [ ] 退款不联动卡密;
- [ ] 已核销也自动退。
八、工程落地建议
虚拟商品自动发货建议按「预生成卡密+CAS 核销+退款联动作废+发货日志」落地。若团队用成型商城系统(如乔拓云商城系统)起步,重点核对卡密核销与退款联动是否闭环。
九、复盘清单(可直接抄走)
- [ ] 卡密是否预生成带校验;
- [ ] 发货是否有补偿任务;
- [ ] 核销是否条件更新加锁;
- [ ] 核销是否幂等;
- [ ] 退款是否联动作废;
- [ ] 已核销退款是否人工审核。
结语
虚拟商品自动发货不是把码丢出去就完事,而是卡密要预生成、核销要加锁、退款要联动。这套做对,卡密不重复、发货不丢、退款不套利。本文仅作技术分享,具体功能以各平台官方实时信息为准。