NodeJS如何处理对MySQL的并发请求

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 (

我对NodeJS有问题。 当我试图发布/更新时

  • 一个余额
  • 一个账户
  • 从两个不同的用户发布
  • 同时进行。
例如:

我有一个带有ExpressJS的API,用于将数据发布到
t\u account
表中,如下所示

每次交易后,我需要先从
max(id)
获取最新余额

我试图得到400而不是300的余额

例如:

  • 起始平衡=100
  • 第一个新员额=100,=>余额=200
  • 第二个新员额=200,=>余额=400
  • 代码示例:

    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功能
  • 您的
    saveBalance',异步函数
    可能是双
    SELECT…SELECT
    double
    INSERT…INSERT
    • 我的直觉告诉我这是基于图像的问题,顺序是错误的
  • 检查数据库设置
  • 如果
    saveBalance',async函数
    没有问题。我会根据MySQL控制台日志检查您的
    数据库设置
    &您正在使用
    localhost

    • 您的图像显示选择…选择…插入…插入
    • 但它应该是选择…插入…**选择…**插入…
  • 这可能是由于MySQL数据库设置存在问题

    • 请检查您的MySQL以检查此运行
  • SQL代码:

    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;";