Javascript 有人破坏了我的提问
我一直在尝试使用查询进行交易;我已经这样做了,首先我检查并执行一个查询来检查用户是否有足够的余额,然后我扣除他的余额并处理事务 问题是,如果你下载一个工具,或者使用一个每秒可以点击200次的宏(我认为),信号发送的速度比查询处理的速度快,因此它仍然会认为用户有足够的余额,而他最终没有,他的余额将变为负值 这是快速代码Javascript 有人破坏了我的提问,javascript,mysql,node.js,Javascript,Mysql,Node.js,我一直在尝试使用查询进行交易;我已经这样做了,首先我检查并执行一个查询来检查用户是否有足够的余额,然后我扣除他的余额并处理事务 问题是,如果你下载一个工具,或者使用一个每秒可以点击200次的宏(我认为),信号发送的速度比查询处理的速度快,因此它仍然会认为用户有足够的余额,而他最终没有,他的余额将变为负值 这是快速代码 var processTransaction = function(userid, cost){ database.query('SELECT `balance` FROM
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);
});
});
};
您需要确保数据库处于一致状态。您可以通过几种方式实现这一点,其中最简单的方式是:
- 使用
阻止访问用户表(并在完成后立即解锁表)。如果你点击200次,不用担心——点击将全部排队,无法同时运行LOCK TABLE user WRITE
SET autocommit=0;
LOCK TABLES t1 WRITE, t2 READ, ...;
... do something with tables t1 and t2 here ...
COMMIT;
UNLOCK TABLES;
当您调用锁表时,InnoDB在内部使用自己的表锁,
MySQL拥有自己的表锁。InnoDB发布其内部表
在下一次提交时锁定,但是为了让MySQL释放其表锁,您需要
必须调用解锁表。您不应该将自动提交设置为1,
因为InnoDB会在之后立即释放其内部表锁
调用锁表和死锁很容易发生。InnoDB
如果autocommit=1,则根本不获取内部表锁,以
帮助旧应用程序避免不必要的死锁
您需要确保数据库处于一致状态。您可以通过几种方式实现这一点,其中最简单的方式是:
- 使用
阻止访问用户表(并在完成后立即解锁表)。如果你点击200次,不用担心——点击将全部排队,无法同时运行LOCK TABLE user WRITE
SET autocommit=0;
LOCK TABLES t1 WRITE, t2 READ, ...;
... do something with tables t1 and t2 here ...
COMMIT;
UNLOCK TABLES;
当您调用锁表时,InnoDB在内部使用自己的表锁,
MySQL拥有自己的表锁。InnoDB发布其内部表
在下一次提交时锁定,但是为了让MySQL释放其表锁,您需要
必须调用解锁表。您不应该将自动提交设置为1,
因为InnoDB会在之后立即释放其内部表锁
调用锁表和死锁很容易发生。InnoDB
如果autocommit=1,则根本不获取内部表锁,以
帮助旧应用程序避免不必要的死锁
利用“排队”体系结构还可以让您更容易地处理并发请求。其概念是将所有请求推送到一个队列中。有一个worker设置为“轮询”这个队列,可能是在某种cron上,从队列中读取数据并分配工作。当worker收到项目时,它将更按顺序发出更新/创建请求,并防止出现争用情况。对于这种类型的行为,您将需要更好地处理异步事件。利用“排队”体系结构还可以让您更容易地处理并发请求。其概念是将所有请求推送到一个队列中。有一个worker设置为“轮询”这个队列,可能是在某种cron上,从队列中读取数据并分配工作。当worker收到项目时,它将更按顺序发出更新/创建请求,并防止出现争用情况。使用这种类型的行为,您需要有更多的能力来处理异步事件。在不选择
的情况下进行UPDATE
怎么样
UPDATE user_balance
SET balance = balance - :value
WHERE user_id = :user_id AND balance >= :value
我相信这种方法和交易本身应该有助于避免达到负平衡
[UPD]为了检测余额是否已实际更新(因为确实存在无效余额),您可以读取受影响的行数(取决于所使用的库,它可以是分离的方法或查询)如果不选择而进行更新
如何
UPDATE user_balance
SET balance = balance - :value
WHERE user_id = :user_id AND balance >= :value
我相信这种方法和交易本身应该有助于避免达到负平衡
[UPD]并且为了检测余额是否已实际更新(因为确实存在无效余额),您可以读取受影响的行数(取决于使用的库,它可以是分离的方法或查询)在mysql中,您可以使用选择。。。用于更新
以锁定row@IłyaBursov‘lock row’?是的,锁定row以防止在另一个线程中进行更新您也可以尝试将所有内容放入一个查询中,例如update user SET balance=balance-x,其中id=y和balance>=x
@riv I当前有许多节以相同的方式使用查询,很遗憾,我需要很长时间才能将所有内容更改为适合一个查询。在mysql中,您可以使用select。。。用于更新
以锁定row@IłyaBursov‘lock row’?是的,锁定row以防止在另一个线程中进行更新您也可以尝试将所有内容放入一个查询中,例如update user SET balance=balance-x,其中id=y和balance>=x
@riv I当前有许多节以相同的方式使用查询,我要花很长时间才能改变一切