NodeJS如何处理对MySQL的并发请求
我对NodeJS有问题。 当我试图发布/更新时NodeJS如何处理对MySQL的并发请求,mysql,node.js,database,express,async-await,Mysql,Node.js,Database,Express,Async Await,我对NodeJS有问题。 当我试图发布/更新时 一个余额 一个账户 从两个不同的用户发布 同时进行。 例如: 我有一个带有ExpressJS的API,用于将数据发布到t\u account表中,如下所示 每次交易后,我需要先从max(id)获取最新余额 我试图得到400而不是300的余额 例如: 起始平衡=100 第一个新员额=100,=>余额=200 第二个新员额=200,=>余额=400 代码示例: router.post('/saveBalance',async function (
一个余额
一个账户
- 从两个不同的用户发布
同时进行。
t\u account
表中,如下所示
每次交易后,我需要先从max(id)
获取最新余额
我试图得到400而不是300的余额
例如:
router.post('/saveBalance',async function (req, res) {
try {
let SQL="SELECT balance FROM t_account WHERE id=(SELECT max(id) FROM t_account WHERE no='"+req.body.no+"')";
let queryResult=await db.myexec(SQL);
let newBalance=queryResult[0].balance+req.body.balance;
let SQL2="INSERT INTO t_account(no,balance) VALUES('"+req.body.no+"',"+newBalance+")";
let queryResult2=await db.myexec(SQL2);
res.status(200).json( {
error:"false",
code:"00",
message:"Balance Bank is saved",
})
} catch (error) {
res.status(400).json( {
error:"true",
code:"03",
message:"Balance Bank failed to saved",
})
}})
问题是当两个用户同时发布数据时,我得到的余额不正确
初始化我的事务的代码示例:
MySQL
控制台日志
最后的余额不正确,显示的是300而不是400
这里出了什么问题?您需要锁定正在读取的行,以便在其他人可以读取该行之前更新该行。查看,特别是更新的
来自文档
仅在以下情况下,使用“选择更新”锁定要更新的行
自动提交被禁用(通过使用START开始事务)
事务或将自动提交设置为0。如果启用了自动提交,
与规范匹配的行未锁定
离开您提供的信息,不知道更多关于NodeJ或您的操作系统、版本、设置等的信息。 这是我的思考过程,就像我看到的每个问题一样 检查基本情况
- 我看到你在自己的电脑上运行这个
- 如果连续运行10多次,行为是否相同?
- 如果最终结果不同,请检查正在关闭的进程
- 如果可能的话,
- 请执行基本计算机检查(重新启动、关闭其他程序)
- 如果可能,也在另一台计算机上检查
saveBalance',异步函数
可能是双SELECT…SELECT
doubleINSERT…INSERT
- 我的直觉告诉我这是基于图像的问题,顺序是错误的
saveBalance',async函数
没有问题。我会根据MySQL控制台日志检查您的数据库设置
&您正在使用localhost
- 您的图像显示选择…选择…插入…插入
- 但它应该是选择…插入…**选择…**插入…
- 请检查您的MySQL以检查此运行
SELECT @@GLOBAL.TX_ISOLATION;
您可能还对使用启动事务感兴趣;
但请确保在配置中启用。这也直接与TX\u隔离相关
我的示例将修改您的查询,如下所示:
let SQL2="START TRANSACTION; INSERT INTO t_account(no,balance) VALUES('"+req.body.no+"',"+newBalance+"); COMMIT;";
尝试其他被接受的代码作为您自己的代码
最后,我也推荐阅读
我希望这能有所帮助。哦,我的上帝,你是我的救世主……我认为问题出在node.js(并发进程)……实际上是在mysql中。我不知道“FOR UPDATE”before..非常感谢您的帮助!!只需添加更多上下文,说明这不仅仅是节点异步问题。考虑一个场景,您的应用程序在多台服务器上运行,您可能会进入类似的竞争条件。是的,MySQL有大量可怕的“开箱即用”问题设置。默认情况下,您的事务级别为读取优先级高于写入优先级,这也是为什么这是我回答的一部分。不要忘记检查并尝试使用SET@@GLOBAL.SQL_MODE=“传统”;这样做更合适,也不会让您感到困惑。默认MySQL允许您在NOTNULL列中插入NULL,或者在您忘记使用datetime而不是timestamp时为您提供零日期,反之亦然。
let SQL2="START TRANSACTION; INSERT INTO t_account(no,balance) VALUES('"+req.body.no+"',"+newBalance+"); COMMIT;";