Node.js + MySQL - обработка транзакций - PullRequest
12 голосов
/ 09 мая 2011

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

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

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

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

Ответы [ 5 ]

6 голосов
/ 08 декабря 2011

Check https://github.com/bminer/node-mysql-queues

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

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

5 голосов
/ 21 мая 2012

В зависимости от того, насколько сложна ваша транзакция, вы можете столкнуться с некрасивым вложением, пытаясь поставить в очередь свои запросы из 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 ;

Ваш код узла будет выглядеть примерно так:

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 голосов
/ 10 мая 2011

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

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

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

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

1 голос
/ 10 мая 2011

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

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

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

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

0 голосов
/ 19 февраля 2014

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

...