You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ExpressJS项目JavaScript代码未按自上而下顺序执行问题咨询

问题核心原因
  • 你用到的db.query是异步非阻塞接口:调用后不会等待数据库返回结果,会直接继续执行后续的同步代码,只有等数据库查询完成后,才会把回调函数推入事件队列执行,所以才出现了先打印latest_row_id 1,后打印result4 2的执行顺序。
  • 你把依赖查询结果的变量计算、插入SQL逻辑写在了回调外部,导致拿到的是初始化的默认值latestRowId = 1,计算出来的newRowID = 2和数据库里已有的ID冲突,触发主键重复报错。
修复方案

方案1:回调嵌套(最简单适配现有写法)

把依赖第一个查询结果的逻辑全部移到第一个db.query的回调内部即可:

//Create New Open Market under the game
let latestRowId = 1;
var sqlQuery2 = "SELECT ID FROM markets ORDER BY LAST_EDITED DESC LIMIT 1";
db.query(sqlQuery2, [], function(err, result4) {
    if (err){
        console.log("Error during /openBetoBetoMarket. Proc_4" + err);
        return res.status(500).json({ msg: "Server Error /openBetoBetoMarket. gameID:" + gameID });
    }
    console.log("result4", result4[0].ID)
    latestRowId = result4[0].ID
    // 后续逻辑全部移到这里
    console.log("latest_row_id", latestRowId);
    const newRowID = latestRowId + 1
    const newMarketId = result[0].MARKET_ID + 1
    const newGameId = gameID
    const newDescription = gameTitle
    console.log("New row id", newRowID, "new market id", newMarketId)

    const sqlQuery = "INSERT INTO markets (ID, MARKET_ID, GAME_ID, DESCRIPTION, LAST_EDITED, WRITER) VALUES (?, ?, ?, ?, NOW(), CURRENT_USER);"
    db.query(sqlQuery, [newRowID, newMarketId, newGameId, newDescription], (err, result4) => {
        if (err){
            console.log("Error during /openBetoBetoMarket. Proc_5 " + err);
            return res.status(500).json({ msg: "Server Error /openBetoBetoMarket. gameID:" + gameID });
        } else if (result4.affectedRows > 0){
            console.log("Created new open market for /openBetoBetoMarket. MarketID: " + newMarketId);
            return res.status(200).json({msg: "Created New Open Market", marketID: newMarketId, isOpen: 1})     
        } else {
            console.log("Error during /openBetoBetoMarket. Proc_5. Inserted but no affected Rows");
            return res.status(500).json({ msg: "Server Error /openBetoBetoMarket. gameID:" + gameID });
        }
    })
});

方案2:Promise + async/await 写法(更易维护,避免回调地狱)

如果你的数据库驱动支持Promise版本的调用,或者可以用util.promisify包装db.query,可以用更清晰的类同步逻辑写法:

const { promisify } = require('util');
const query = promisify(db.query).bind(db); // 把callback形式的query转为Promise形式

// 业务逻辑写在async函数内
async function createMarket() {
    try {
        const sqlQuery2 = "SELECT ID FROM markets ORDER BY LAST_EDITED DESC LIMIT 1";
        const result4 = await query(sqlQuery2, []);
        const latestRowId = result4[0].ID;
        console.log("latest_row_id", latestRowId);

        const newRowID = latestRowId + 1
        const newMarketId = result[0].MARKET_ID + 1
        const newGameId = gameID
        const newDescription = gameTitle
        console.log("New row id", newRowID, "new market id", newMarketId)

        const sqlQuery = "INSERT INTO markets (ID, MARKET_ID, GAME_ID, DESCRIPTION, LAST_EDITED, WRITER) VALUES (?, ?, ?, ?, NOW(), CURRENT_USER);"
        const insertRes = await query(sqlQuery, [newRowID, newMarketId, newGameId, newDescription])
        if (insertRes.affectedRows > 0) {
            console.log("Created new open market for /openBetoBetoMarket. MarketID: " + newMarketId);
            return res.status(200).json({msg: "Created New Open Market", marketID: newMarketId, isOpen: 1})
        }
        throw new Error("Inserted but no affected Rows")
    } catch (err) {
        console.log("Error during /openBetoBetoMarket: ", err)
        return res.status(500).json({ msg: "Server Error /openBetoBetoMarket. gameID:" + gameID });
    }
}
createMarket()
额外优化建议
  • 不建议自行计算主键ID,建议将数据库表的ID字段设置为自增主键,插入时不需要传ID字段,数据库会自动生成不重复的ID,从根本上避免主键冲突问题。
  • 并发场景下即使按上面的异步逻辑写,也可能出现两个请求同时查到相同的latestRowId,计算出相同的newRowID导致冲突,用自增主键可以完全规避这个问题。

内容的提问来源于stack exchange,提问作者Joebert Rosales

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.01 10:09:03