我一直在尝试使用查询进行交易;我已经这样做了,首先,我检查并执行查询以检查用户是否有足够的余额,其次,我要扣除他的余额并处理交易。
问题是,如果您下载工具,或使用可以每秒点击200次的宏(我认为),信号发送的速度比查询处理的速度快,因此它仍然会认为用户有足够的余额,然后他结束没有,他的平衡将变为负数。
这是快速代码
var processTransaction = function(userid, cost){
database.query('SELECT `balance` FROM `user` WHERE `id` = ' + database.pool.escape(userid), function(err, row){
if(err){
return;
}
if(!row.length){
return;
}
var userBalance = row[0].balance;
if(userBalance >= cost){
/* User has enough, process */
addBalance(userid, -cost); //deduct query
}
});
}
我在这里犯任何错误,我会采取不同的方法吗?
查询功能
var query = function(sql, callback) {
if (typeof callback === 'undefined') {
callback = function() {};
}
pool.getConnection(function(err, connection) {
if(err) return callback(err);
connection.query(sql, function(err, rows) {
if(err) return callback(err);
connection.release();
return callback(null, rows);
});
});
};
最佳答案
您需要确保数据库处于一致状态。您可以通过几种方法来执行此操作,其中最简单的方法是:
使用LOCK TABLE user WRITE
阻止访问用户表(完成后立即解锁表)。如果您单击200次,请放心-点击将全部排队,并且无法同时运行。
来自the manual:
正确使用LOCK TABLES和UNLOCK TABLES的方法
事务表(例如InnoDB表)将开始事务
SET自动提交= 0(不开始交易),然后锁定
TABLES,并且在提交事务之前不要调用UNLOCK TABLES
明确地。例如,如果您需要写入表t1并读取
从表t2,您可以执行以下操作:
SET autocommit=0;
LOCK TABLES t1 WRITE, t2 READ, ...;
... do something with tables t1 and t2 here ...
COMMIT;
UNLOCK TABLES;
当您调用LOCK TABLES时,InnoDB在内部获取其自己的表锁,
MySQL拥有自己的表锁。 InnoDB发布其内部表
在下一次提交时锁定,但要让MySQL释放表锁,您需要
必须调用解锁表。您不应该具有自动提交= 1,
因为InnoDB之后会立即释放其内部表锁
调用LOCK TABLES和死锁很容易发生。创新数据库
如果autocommit = 1,则根本不获取内部表锁
帮助旧应用程序避免不必要的死锁。