1

我正在使用带有连接池和连接限制为 10 的 node-mysql2。当我重新启动应用程序时,结果很好 - 它们与我在 db 上的匹配。但是当我开始插入新记录并重做相同的选择查询时,我会得到间歇性的结果,缺少我刚刚添加的最新记录。

如果我直接检查数据库,我可以看到我刚刚通过我的应用程序添加的记录。只是应用程序无法以某种方式看到它。

我认为这是一个错误,但这是我的代码设置方式:

module.exports.getDB = function (dbName) {
    if (!(dbName in dbs)) {
        console.log(`Initiating ${dbName}`);
        let config = dbConfigs[dbName];
        dbs[dbName] = mysql.createPool({
            host: config.host,
            port: config.port || 3306,
            user: config.user,
            password: config.password,
            connectionLimit: 10,
            database: config.database,
            debug: config.debug
        });
    }
    return dbs[dbName]; // I just initialize each database once
};

这是我的选择查询:

let db = dbs.getDB('myDb');
const [rows] = await db.query(`my query`);
console.log(rows[0]); // this one starts to show my results inconsistently once I insert records

这是我的插入查询:

module.exports = {
    addNote: async function(action, note, userID, expID) {
        let db = dbs.getDB('myDb');

        await db.query(`INSERT INTO experiment_notes (experiment_id, action, created_by, note)
                            VALUES (?, ?, ?, ?)`, [expID, action, userID, note]);
    }
};

如果我将 connectionLimit 设置为 1,我将无法重现问题……至少现在还没有

知道我做错了什么吗?

4

1 回答 1

1

将 your 设置connection_limit为 1 有一个有趣的副作用:它将所有从节点程序到数据库的访问序列化。每个操作,无论是 INSERT 还是 SELECT,都必须在下一个操作开始之前运行完成,因为它必须等待池中的一个连接释放。

您间歇性丢失的行可能是由于从池中的不同连接同时访问您的 DBMS。如果您在 MySQL 处理来自另一个连接的 INSERT 时从一个连接执行 SELECT,则 SELECT 不会总是找到正在插入的行。这是一个特点。它是ACID(原子性、一致性、隔离性、持久性)的一部分。ACID 对于扩大 DBMS 至关重要。

在比您向我们展示的应用程序更复杂的应用程序中,当您使用 DBMS 事务而忘记提交它们时,也会发生同样的事情。

编辑多个数据库连接,甚至来自同一程序中同一池的连接,彼此独立工作。因此,如果您在一个连接上执行尚未提交的事务并在另一个连接上执行查询,则查询将(通常)反映事务开始之前的数据库状态。查询不能强制事务回滚,除非它以某种方式导致死锁。但是死锁会产生错误信息;你可能没有看到任何东西。

有时,您可以通过在同一连接上使用SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;. 这可以在繁忙的 DBMS 上稍微提高查询性能,并防止一些死锁,只要您愿意让您的查询只看到事务的一部分。我将它用于历史查询(昨天发生的事情)。它记录在这里。默认值,即解释您所看到内容的那个,是SET TRANSACTION LEVEL REPEATABLE READ;

但是,在需要之前避免使用那种隔离级别的东西。(该建议属于“太聪明就是愚蠢”的总标题。)

于 2020-03-02T12:46:42.217 回答