node-mysql2: набор результатов не отражает последние результаты - PullRequest
1 голос
/ 27 февраля 2020

Я использую node-mysql2 с пулом соединений и пределом соединения 10. Когда я перезапускаю приложение, результаты хорошие - они совпадают с тем, что у меня есть на БД. Но когда я начинаю вставлять новые записи и повторять одни и те же запросы выбора, я получаю прерывистые результаты, пропуская последнюю добавленную запись.

Если я проверю базу данных напрямую, я смогу увидеть записи, которые я только что добавил через свое приложение. Это только приложение, которое не может его как-то увидеть.

Я думаю, что это ошибка, но вот как у меня настроен код:

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, я не смогу воспроизвести проблему ... по крайней мере, пока

Любая идея что я делаю не так?

1 Ответ

1 голос
/ 02 марта 2020

Установка значения connection_limit в 1 имеет интересный побочный эффект: он сериализует весь доступ от вашей программы узла к вашей базе данных. Каждая операция, будь то INSERT или SELECT, должна выполняться до завершения следующей, потому что она должна ожидать освобождения одного соединения в пуле.

Вероятно, что периодически пропускаемые строки происходят из-за одновременный доступ к вашей СУБД из разных соединений в вашем пуле. Если вы выполняете SELECT из одного соединения, когда MySQL обрабатывает INSERT из другого соединения, SELECT не всегда найдет вставляемую строку. Это особенность. Это часть ACID (атомарность, консистенция, изоляция, долговечность) . ACID жизненно важен для расширения масштабов СУБД.

В более сложных приложениях, чем те, которые вы нам показали, то же самое может произойти, когда вы используете транзакции СУБД и забываете их коммитить.

Редактировать Несколько соединений с базой данных, даже соединения из одного и того же пула в одной программе, работают независимо друг от друга. Таким образом, если вы выполняете еще не подтвержденную транзакцию для одного соединения и запрос для другого соединения, запрос будет (обычно) отражать состояние базы данных до начала транзакции. Запрос не может принудительно откатить транзакцию, если он не вызывает взаимоблокировку. Но тупики генерируют сообщения об ошибках; вы, вероятно, не видите ничего.

Иногда вы можете контролировать то, что видит запрос, предшествуя ему в том же соединении с SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;. Это может в загруженной СУБД немного повысить производительность запросов и предотвратить некоторые тупики, если вы хотите, чтобы ваш запрос видел только часть транзакции. Я использую это для исторических запросов (что случилось вчера). Это задокументировано здесь . По умолчанию, который объясняет то, что вы видите, это SET TRANSACTION LEVEL REPEATABLE READ;

Но избегайте такого рода вещей уровня изоляции, пока они вам не понадобятся. (Этот совет называется «слишком умный - глупый».)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...