假设我有某种游戏。我有一个像这样的 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/