如何正确处理异步并发请求? [英] How to handle async concurrent requests correctly?

查看:161
本文介绍了如何正确处理异步并发请求?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我有一些游戏。我有一个这样的buyItem函数:

  buyItem:function(req,res){
//查询用户余额
//扣除用户余额
//购买项目
}

如果我垃圾邮件,直到用户余额被扣除(第二个查询),用户的余额仍然是正数。



我尝试过:

  buyItem:function(req,res){
if(req.session.user.busy)return false;
req.session.user.busy = true;
//查询用户余额
//扣除用户余额
//购买项目
}

问题是 req.session.user.busy 未定义为第一〜五个请求。所以这也不行。



我们如何处理这种情况?我正在使用Sails.JS框架,如果这很重要。

解决方案


更新



正如几位评论者所注意到的,当连接池已启用。在最初发布的时候,并不是所有的适配器都默认合并,但是在这一点上应该假设它们是这样做的,所以每个方法都调用( .query() .findOne()等)可能在不同的连接上,并在事务之外进行操作。 Waterline的下一个主要版本将具有事务支持,但直到那时,确保您的查询是事务性的唯一方法是使用原始数据库驱动程序包(例如 pg mysql )。 p>

听起来你需要的是一个交易的。 Sails不支持框架级别的交易(在路线图上),但如果您使用的是支持它们的数据库(如Postgres或MySQL),则可以使用 .query()方法访问底层适配器,并运行本地命令。这里有一个例子:

  buyItem:function(req,res){
try {
//开始交易
User.query(BEGIN,function(err){
if(err){throw new Error(err);}
//查找用户
用户.findOne(req.param(userId)。exec(function(err,user){
if(err){throw new Error(err);}
//更新用户余额
user.balance = user.balance - req.param(itemCost);
//保存用户
user.save(function(err){
if(err){抛出新的错误(err);}
//提交事务
User.query(COMMIT,function(err){
if(err){throw new Error(err) }
//显示更新的用户
res.json(user);
});
});
});
});
}
//如果有任何问题,回滚事务
catch(e){
User.query(ROLLBACK,function(e rr){
//回滚失败 - 灾难性错误!
if(err){return res.serverError(err);}
//返回导致回滚的错误
return res.serverError(e);
});
}
}


Let's say I have some sort of game. I have a buyItem function like this:

buyItem: function (req, res) {
    // query the users balance
    // deduct user balance
    // buy the item
}

If I spam that route until the user balance is deducted (the 2nd query) the user's balance is still positive.

What I have tried:

buyItem: function (req, res) {
    if(req.session.user.busy) return false;
    req.session.user.busy = true;
    // query the users balance
    // deduct user balance
    // buy the item
}

The problem is req.session.user.busy will be undefined for the first ~5 requests. So that doesn't work either.

How do we handle such situations? I'm using the Sails.JS framework if that is important.

解决方案

Update

As several commenters have noted, the code below doesn't work when connection pooling is enabled. At the time that this was originally posted, not all of the adapters pooled by default, but at this point it should be assumed that they do, so that each individual method call (.query(), .findOne(), etc.) could be on a different connection, and operating outside of the transaction. The next major version of Waterline will have transaction support, but until then, the only way to ensure that your queries are transactional is to use the raw database driver package (e.g. pg or mysql).

It sounds like what you need is a transaction. Sails doesn't support transactions at the framework level yet (it's on the roadmap) but if you're using a database that supports them (like Postgres or MySQL), you can use the .query() method of your model to access the underlying adapter and run native commands. Here's an example:

buyItem: function(req, res) {
  try {
    // Start the transaction
    User.query("BEGIN", function(err) {
      if (err) {throw new Error(err);}
      // Find the user
      User.findOne(req.param("userId").exec(function(err, user) {
        if (err) {throw new Error(err);}
        // Update the user balance
        user.balance = user.balance - req.param("itemCost");
        // Save the user
        user.save(function(err) {
          if (err) {throw new Error(err);}
          // Commit the transaction
          User.query("COMMIT", function(err) {
            if (err) {throw new Error(err);}
            // Display the updated user
            res.json(user);
          });
        });
      });
    });
  } 
  // If there are any problems, roll back the transaction
  catch(e) {
    User.query("ROLLBACK", function(err) {
      // The rollback failed--Catastrophic error!
      if (err) {return res.serverError(err);}
      // Return the error that resulted in the rollback
      return res.serverError(e);
    });
  }
}

这篇关于如何正确处理异步并发请求?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆