我一直在尝试使用查询进行交易;我已经这样做了,首先,我检查并执行查询以检查用户是否有足够的余额,其次,我要扣除他的余额并处理交易。

问题是,如果您下载工具,或使用可以每秒点击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,则根本不获取内部表锁
  帮助旧应用程序避免不必要的死锁。

10-05 20:36
查看更多