优惠券 | 兑换码

一、优惠券使用流程

分为手动领取、兑换码领取两种方式

1、手动领取

流程:

1、查询优惠券

2、校验使用时间

3、校验库存

4、校验领取数量

5、更新发放数量

6、新增用户券

前面四步我们需要频繁的访问数据库,这样对数据造成过载。我们可以将前四步设计成操作redis、将优惠券的信息,使用redis的hash类型,存储到redis缓存数据库里面。

2、兑换码领取

兑换码,我们要防止被用户猜出来,和高刷、防止恶意攻击,要数据量大、不可重复兑换、高效。

这一步我们采用base32编码,和借鉴jwt令牌的格式。生成优惠券兑换码。

首先,先知道什么是base32编码。base32编码就是将一个50位的二进制数、每5位对应一个字符,(5个1最大就是32)这样就能得到10位的优惠券兑换码。

兑换码:

兑换码由三部分组成:

第一部分称为序列号(32位),由id自增生成的十进制整数,我们把这个数转换成二进制、截取最后的14位、高位补0。

第二部分称为新鲜值(4位),优惠券的id,将优惠券id转换成二进制,截取4位(4个1最大16)、高位补0。我们设置一个二维数组的密匙,这个密匙16组,每一组9个数字。因为4个二进制位最大就是16。

第三部分称为签名(14位),由序列号+新鲜值,按位乘以密匙,得到一个十进制数,将这个十进制转换成二进制,截取14位、高位补0。

解释:

序列号32位、每四位一组,就是8个十进制数。

新鲜值4位、四位一组就是1个十进制数。

密匙有16组、通过新鲜值匹配哪一组,每一组9个十进制数,刚好对应序列号和新鲜值加起来的9个十进制数。依次相乘,就得到了签名

二、超卖问题:

我们理想的状态是:

查询优惠券、判断是否充足、充足则更新优惠券领取数量

但是这样不能保证原子性,比如:

a线程还没有减库存,b线程进来了,导致超卖。

解决方法:乐观锁,依赖数据库的行锁,加一个字段,记录优惠券卖了多少张,每次更新进行一次判断。

三、超领问题:

用户刷卷,导致一个用户领取了多张优惠券。

解决方式:

悲观锁(同步锁)

因为当时我们锁的用户id,用户id使用了tostring方法,因为这个方法的源码里面new了新对象,所以锁不住。使用intern()方法解决

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值