关于nodejs并发的一些疑问
发布于 10 年前 作者 whxaxes 7819 次浏览 最后一次编辑是 8 年前

我是刚学习nodejs不久的菜鸟,最近学习的时候遇到个问题,想问一下: 我一个项目里面,项目里有奖品,奖品有1个。当为0个时就领取失败 前端有个按钮可以点击领取奖品,此时同时有2个人点击领取。我在后台的写法就是,先查询奖品个数,也就是 先conn.query(“select * from giftinfo” , function(row){ }) 获取到奖品个数,然后就在回调中进行计算,把奖品个数减一再更新上去。也就是在回调里再进行conn.query(“update …” , function(){})

我自己的项目里在回调中还有几个数据库更新操作,现在的情况就是,同时点击的话,有时会出现奖品只有1个,但是却2个人都领到了奖品。 我自己想了一下,是不是当同时点击时,首先一个人先触发conn.query方法查询,此时查询结果还没返还的时候,nodejs又去执行第二个人的query,于是在两个的查询回调当中,奖品的数量都是一致的,所以都是可以领取。

请问这种情况一般是如何处理的呢?

11 回复

想起之前看的课堂,将的是如何处理12306抢票的问题。

貌似用的解决办法是锁什么的。

var events= require(‘events’); var x = new events.EventEmitter(); var jpCount = 5; //conn.query(“select * from giftinfo” , function(row){ })

x.on(‘lingjiang’,lingjiangHandle); function lingjiang(user) { if (jpCount > 0) x.emit(‘lingjiang’, user); else { console.log(‘奖品已领玩’); } }

var lingjiangHandle = function(user) { jpCount–; if (lingjiangSucceed) { console.log(user + ‘领奖成功’); } else { console.log(user + ‘领奖失败’); jpCount++; } }

mongo没有锁的概念,这时候可以考虑使用redis

这么做是不正确的。

很明显,你对数据库做了写操作,单单查询来判断是不够的。必须修改数据库成功,才能为用户颁发奖品,如果失败,则意味奖品不存在。

还有一种就是同步缓存,在nodejs服务器记录一个奖品数作为查询和递减,数据库服务器只负责修改。但是nodejs服务器挂掉会导致这个缓存消失,每次重新启动nodejs服务器,需要先去数据库服务器确认当前可以领的奖品数。

mongodb是存在写锁的。

@sandheart 谢谢,我知道该如何做了

@tulayang 好的,我知道该如何做了,感谢教导

用缓存。缓存对于事件I/O几乎0延迟。

看着这个issue之后, 解决掉了机器人并发刷邮件的严重问题. 多谢4楼.

楼上各位说得真好

可以用一个锁,点击后,只有抢到锁的请求可以继续执行数据库操作。 具体锁怎么实现就多种多样了:

  1. 可以使用一个互斥队列,rabbitmq。
  2. 可以利用mongodb更新单个数据是原子操作这一特性,建一张表,里面放一条数据,有一个列为locked,默认是false,每次点击首先去执行更新这条数据的操作,将locked=true,更新成功的即为抢到了锁。
回到顶部