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, правильно?