0%

一个简单的抢红包功能设计

前言

提到抢红包,我就直摇头,这种类似秒杀的功能以前没有接触过,何况是这种直接针对金钱的操作。对于陌生的环境我一向有些抵触,因为要花好一阵儿去适应,但是一旦能嗅到其中的规则,我就会了乐此不疲。

抢红包设计

秒杀类功能主要是保证减库存操作的一致性,抢红包则要考虑两个方面:减库存和减金额。在不考虑性能的情况下,如果是单机架构,直接加上一层 synchroized 锁即可;在分布式情况下,则可以使用分布式锁,例如 redisson
抢红包的操作其实可以分为两步:用户抢一个金额,给用户发放金额。在第一版程序中,我是通过数据库中的 已领取金额已领取数量 两个字段来进行 “减库存” 和 “减金额” 操作(实际是加),代码如下。

1
2
3
4
5
6
update t_app_wallet_record
set received_amount = received_amount + #{amount}
used_bags = used_bags + 1
where wallet_serial_no = #{walletSerialNo}
and used_bags < bags
and total_amount >= received_amount + #{amount}

在和同事讨论了一下之后,发现可以再优化一下。原先用户抢到的金额,是在他执行抢这个动作时才分配。现在改成发红包时直接先分配红包金额,存入 redis 中,抢红包时从 redis 中拿到一个金额,如果程序执行失败(例如修改数据库失败),再将金额还给 redis
最后附上代码:

1