node.js - 如何正确处理异步并发请求?

标签 node.js express concurrency sails.js

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

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

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

我尝试过的:

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 对于前 ~5 个请求将是 undefined。所以这也不起作用。

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

最佳答案

Update 2

Sails 1.0 now has full transaction support, via the .getDatastore() method. Example:

// 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)`.
});

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

听起来您需要的是 transaction . Sails 尚不支持框架级别的事务(它在路线图上),但如果您使用的是支持它们的数据库(如 Postgres 或 MySQL),则可以使用 .query()访问底层适配器并运行模型的方法 native commands .这是一个例子:

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);
    });
  }
}

关于node.js - 如何正确处理异步并发请求?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25079408/

相关文章:

node.js - 如何从外部 Node/Express 服务器重定向页面

c# - 基于参数锁定

c++ - 有没有办法将 std::async 与 std::experimental::future 一起使用?

java - 设置理想的线程池大小

node.js - Node 'readline' 如何检测当前行是文件中的最后一行

node.js - 有没有办法在 Sequelize 的 isAlpha 验证中包含特殊字符?

node.js - app.all ('*' ) 和 app.use ('/' ) 之间的区别

javascript - 无法访问 req.user 的属性

javascript - Express 4.x 路由器和 Angular 有问题吗?

mongodb - NodeJS & Mongoskin,不能做简单的更新。传入的参数必须是 12 字节或 24 十六进制字符串