首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何正确处理异步并发请求?

如何正确处理异步并发请求?
EN

Stack Overflow用户
提问于 2014-08-01 11:38:56
回答 2查看 5.6K关注 0票数 2

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

代码语言:javascript
复制
buyItem: function (req, res) {
    // query the users balance
    // deduct user balance
    // buy the item
}

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

我试过的是:

代码语言:javascript
复制
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
}

问题是,对于第一个~5个请求,req.session.user.busy将是undefined。所以这也没用。

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

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2014-08-02 23:07:42

更新2 Salles1.0现在已经通过事务支持方法获得了完整的.getDatastore()。示例:

代码语言:javascript
复制
// Get a reference to the default datastore, and start a transaction.
await sails.getDatastore().transaction(async (db, proceed)=> {
  // Now that we have a connection instance in `db`, pass it to Waterline
  // methods using `.usingConnection()` to make them part of the transaction:
  await BankAccount.update({ balance: 5000 }).usingConnection(db);
  // If an error is thrown, the transaction will be rolled back.
  // Or, you can catch errors yourself and call `proceed(err)`.
  // To commit the transaction, call `proceed()`
  return proceed();
  // You can also return a result with `proceed(null, result)`.
});

更新 正如一些评论者所指出的,当启用连接池时,下面的代码无法工作。在最初发布时,并不是所有的适配器默认都是池的,但此时应该假定它们是这样做的,因此每个单独的方法调用(.query().findOne()等)。可能在另一个连接上,并在事务之外操作。下一个主要版本的Waterline将提供事务支持,但在此之前,确保查询是事务性的唯一方法是使用原始数据库驱动程序包(例如pgmysql)。

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

代码语言:javascript
复制
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);
    });
  }
}
票数 14
EN

Stack Overflow用户

发布于 2014-08-03 00:33:43

我还没试过这个。但是,只要您不使用多个实例或集群,就应该能够将状态存储在内存中。因为节点是单线程的,所以原子性不应该有任何问题。

代码语言:javascript
复制
var inProgress = {};

function buyItem(req, res) {
    if (inProgress[req.session.user.id]) {
        // send error response
        return;
    }

    inProgress[req.session.user.id] = true;

    // or whatever the function is..
    req.session.user.subtractBalance(10.00, function(err, success) {
        delete inProgress[req.session.user.id];

        // send success response
    });
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/25079408

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档