我写的伪代码如下,但出现了个bug,抽奖现在要限制每日抽奖结果出现的次数,但实际运行是在并发时不能限制住,如何解决?
resultDayLimitTimes = {
resultA => 2 # 每天最多出现2次
resultB => 5 # 每天最多出现5次
resultC => 20 # 每天最多出现20次
resultD => Infinite # 每天出现次数没有限制
}
Begin transaction
select * from lottery_chance where id =XX and result = null limit 1 for update
#bug 就在下面这个循环里,如果resultA今天已经出现过一次了,
#然后有2个人(这2人的XX是不同的,所以前面的for update对
#于这种并发不能限制,前面的for update是用来防止同一次抽奖机会被并发时使用多次的)
#同时抽到YY=resultA,由于事务还未提
#交那么yyCount都是1,小于每日限制2,于是跳出循环,这2人
#都中了resultA,这时当天出现了3个resultA 超出2个限制,
#我应该怎么写才能解决这个问题?
while true {
YY = randomIn [resultA,resultB,resultC,resultD]
yyCount = select count(*) from lottery_chance where result=YY and used_time > todayDate
if yyCount < resultDayLimitTimes[YY] {
break
}
}
update lottery_chance set result=YY, used_time = now where id =XX
Commit
暂时能想到的是:
再增加一个表来专门记录某天某个result的发放次数,缺点是需要预先创建好期间每天每个result初始数据,并且循环里使用行锁在高并发里效率就非常低了,这是不能被接受的:<