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

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

问题描述

假设我有某种游戏。我有一个buyItem函数像这样:

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
}

如果我在该使用者余额被扣除(第2次查询)之前发送垃圾邮件,则该用户的余额仍为正数。

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

我尝试过的操作:

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
}

问题是 req.session.user.busy 将会是 undefined 为第一〜5个请求。所以这也不工作。

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

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

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

推荐答案


更新



正如几个评论者指出的,下面的代码在连接池。在最初发布时,并非所有的适配器默认情况下都是合并的,但在这一点上应该假设它们这样做,以便每个单独的方法调用( .query() .findOne()等)可以在不同的连接上,并在事务外部操作。下一个主要版本的Waterline将有事务支持,但在那之前,确保您的查询是事务性的唯一方法是使用原始数据库驱动程序包(例如 pg mysql )。 p>

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).

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

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天全站免登陆