node.js - 抽奖码设计问题
天蓬老师
天蓬老师 2017-04-17 15:17:18
0
3
697

程序的逻辑:

程序事先生成了抽奖码存在mysql中,然后有用户来的以后,找到一个没有用过的抽奖码给他,然后把这个抽奖码设置成为已经使用过了

问题:
当大量用户同时并发请求的时候,大部分用户返回同一个抽奖码

原因大概是这样子的

select codeid,codevalue from tb_code where isused=0 Limit 1

通过上面的sql找到一个没有使用过的抽奖码

 update tb_code set isused=1 where codeid=codeid

然后上面的sql语句是更新为已经使用

当大量用过过来的时候,比如A先取到一个码XYBV,但是还没有更新,B用户也过来了的时候找到的也是这个码值了。

code的返回都是在执行完update以后返回

后来修改了下更新语句

update tb_code set isused=1 where isused=0 and codeid=codeid

根据affectedRows来判断是不是更新成功了,如果成功的话,则返回code,否返回一个null

这样虽然不会返回重复的值,但是会有一部分收不到码值

再后来的搜了下,使用直接更新查找到码值,最后再通过ranomno来查找刚才更新的码值,如下面所示的sql

  update tb_code set isused=1,randomno='+randomno+' where codeid in ( select 
  codeid from (select codeid from tb_code where isused=0 Limit 1) as 
  arbitraryTableName)';

刚开始本地测试的时候,没有问题,想着解决了。后来上线,检测日志的时候,发现很多请求长时间没有响应,应该是上面的sql语句执行的效率太低了。

最后换了一种方法使用redis缓存code

先从库里面取1000个code使用Lpush放去redis里面去,然后当用户有请求过来,直接从redis里面取Rpop

然后做一个定时任务,检测redis里面的code数量,如果少于设定的数量,就从库里面取1000个Lpush到redis里面去

现在项目跑了几个小时,暂时没有发现请求超时的问题和码值重复的问题。

但是感觉这种方式凑合能用,但不是最好的

想请问大家,对于类似的问题有没有最佳实践,比如在数据库设计和程序结构上

天蓬老师
天蓬老师

欢迎选择我的课程,让我们一起见证您的进步~~

reply all(3)
大家讲道理

You can generate all the codes in advance and put them in redis, so you don’t have to worry about it again.

You can also use mongodb, the concurrency performance of querying and modifying the database is also very strong;

黄舟

Can you try mysql transactions?
http://dwz.cn/3SrgGk

迷茫

The lottery code is immediately calculated based on the uid and a random string is added

Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template