Node.js + MySQL - обработка транзакций

Я создаю приложение на node.js, используя экспресс и драйвер node -mysql. В моем приложении есть несколько случаев, когда мне нужно сделать ряд вложений/обновлений базы данных. Я хочу, чтобы они были в транзакции таким образом, что если вторая или третья не сработает, предыдущие вставки полностью откатываются.

В настоящее время, как я делаю это, нужно иметь какое-то промежуточное ПО, которое выполняет START TRANSACTION, когда поступит запрос. Во время обработки запроса, если возникает какая-либо ошибка, я поймаю эту ошибку и сделаю a ROLLBACK. Если ошибка не возникает, я делаю COMMIT перед отправкой ответа в браузер.

Однако теперь я обеспокоен тем, что это не сработает, когда несколько пользователей обращаются к приложению одновременно, поскольку MySQL делает принудительное завершение, если другой запрос пытается начать свою собственную транзакцию с помощью START TRANSACTION! В настоящее время я использую только один экземпляр node и одно соединение MySQL для всех запросов.

Может кто-нибудь, пожалуйста, посоветуйте мне, если мои проблемы действительны, и как мне получить поддержку транзакций?

Ответ 1

Вам нужно создать пул клиентов или каким-то иным образом обеспечить, чтобы две разные страницы не вставляли команды в одно и то же соединение (по крайней мере, хотя любой из них находится в транзакции).

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

Вы можете создать и управлять своей собственной очередью, но это приведет к сериализации всех транзакционных страниц (при условии, что вы придерживаетесь модели единого подключения).

Из быстрого поиска в Google выглядит несколько пулов node -mysql на github. Однако, глядя на них, они не похожи на то, что они помогут в вашей проблеме.

Ответ 2

Отъезд https://github.com/bminer/node-mysql-queues

Я реализовал небольшую оболочку для node -mysql для поддержки транзакций и нескольких операторов. Он не был протестирован и не готов к производству... но это будет через несколько дней.:)

ОБНОВЛЕНИЕ. Я уже давно тестировал эту библиотеку... должно быть хорошо!

Ответ 3

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

Вместо этого вы можете написать хранимую процедуру и завершить ее с помощью SELECT с флагом успеха/сбоя, затем запросить процедуру с помощью node-mysql как вы бы запросили SELECT. Вот как выглядит хранимая процедура:

DELIMITER //
DROP PROCEDURE IF EXISTS MyProcedure //
CREATE PROCEDURE MyProcedure(IN param1 VARCHAR/*, My, Parameters, ... */)
BEGIN

    DECLARE EXIT HANDLER FOR NOT FOUND, SQLWARNING, SQLEXCEPTION
    BEGIN
        ROLLBACK;
        SELECT 0 AS res;
    END;

    START TRANSACTION;
    # My Transaction ...


    COMMIT;
    SELECT 1 AS res;

END //
DELIMITER ;

Ваш код Node выглядит примерно так:

var mysql = require('mysql');

var client = mysql.createClient({
    host    : '127.0.0.1',
    user    : 'username',
    password: 'password'
});
client.query('USE mydatabase');

var myParams = "'param1', 'param2', ... ";
client.query("CALL MyProcedure(" + myParams + ")", function(err, results, fields) {
    if (err || results[0].res === 0) {
        throw new Error("My Error ... ");
    } else {
        // My Callback Stuff ...

    }
});

Ответ 4

Мне трудно поверить, что если отдельный сеанс выполняет START TRANSACTION, что совершаются другие транзакции. Это было бы совершенно небезопасно, особенно когда данные должны быть отброшены (или "откат"?).

Возможно ли, что вы смешиваете это с тем же сеансом START TRANSACTION?
См. http://dev.mysql.com/doc/refman/5.0/en/implicit-commit.html, где объясняется, что транзакции не могут быть вложенными. Это, конечно, относится к одному сеансу, а не к другому сеансу пользователя.

Предполагая, что вы не перепутались с уровнем изоляции вашего сеанса или глобальным уровнем изоляции, транзакции должны быть безопасными.

В любом случае, если вы хотите поставить в очередь свои транзакции, нетрудно создать объект глобальной очереди в node и связать вызовы (так что один начинается, когда другой заканчивается). Простой массив с push и pop должен делать трюк.

Ответ 5

Просто идея: на postresql вы можете начать транзакцию и установить для нее ID. Итак, вы можете повторно использовать одно и то же соединение, потому что если вам нужно совершить или откат, вы будете ссылаться на свою транзакцию по id, правильно?