Node.js + MySQL – 处理事务

我正在使用express和node-mysql驱动程序在node.js上构build应用程序。 当我需要进行一系列数据库插入/更新时,我的应用程序中有几个案例。 我希望他们在一个事务中,如果第二个或第三个失败,以前的插入完全回滚。

目前,我这样做的方式是有一种中间件,在请求到达时执行START TRANSACTION 。 在处理请求的过程中,如果发生任何错误,我会捕获此错误,并执行ROLLBACK 。 如果没有错误发生,我发送响应给浏览器之前做一个COMMIT

不过,现在我担心,当多个用户同时访问应用程序时,这不起作用,因为如果另一个请求尝试使用START TRANSACTION开始自己的事务,MySQL会强制执行提交! 我目前只使用一个节点的实例,并为所有请求使用一个MySQL连接。

如果我的担忧是有效的,有人能请教我吗?如何获得交易支持?

您将需要创build一个客户端池,或者以某种方式确保两个不同的页面不在相同的连接中散布命令(至less在任何一个事务处于事务中时)。

既然你想根据前面的命令有条件地做一个回滚,你需要通过callback链接数据库调用,而不是依赖node-mysql排队行为。 这将打开一个窗口,让其他页面进入,并按照您的build议在同一个连接上排队操作。

你可以创build和pipe理你自己的队列,但是最终会将所有事务页面序列化(假设你坚持单一的连接模型)。

从一个快速的谷歌search,它看起来像Github上有几个节点的MySQL池。 然而,看了他们之后,他们看起来并不会帮助你解决问题。

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

我为node-mysql实现了一个小包装来支持事务和多个语句。 它没有经过testing,并没有准备好生产……但是这将在几天内完成。 🙂

更新 :我已经很好地testing了这个库,现在应该很好去!

根据交易的复杂程度,您可能会遇到一些难看的嵌套,试图从Node中排列您的查询,这可能会引入丑陋的variables范围问题。

你可以做什么,而不是写一个存储过程,并通过SELECT一个成功/失败标志结束它,然后像查询SELECT查询与node-mysql程序。 以下是存储过程的外观:

 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 ... } }); 

我觉得很难相信,如果一个单独的会话执行一个START TRANSACTION ,那么其他的事务就被提交了。 这将是完全不安全的,尤其是当数据需要回滚(或“回滚”)时。

是否有可能将这一点与同一个会话 START TRANSACTION
请参阅http://dev.mysql.com/doc/refman/5.0/en/implicit-commit.html ,其中解释了事务不能嵌套。 这当然适用于同一会话 ,而不适用于其他用户的会话。

假设你没有搞乱你的会话的隔离级别或者全局隔离级别,那么事务应该是安全的。

在任何情况下,如果你想对事务进行排队,在节点中build立一个全局的队列对象并且连接调用并不困难(所以当另一个完成时就开始)。 一个简单的数组与推动和stream行应该做的伎俩。

只是一个想法:在Postresql上,您可以启动一个事务并为其设置一个ID。 那么,你可以重复使用相同的连接,因为如果你需要提交或回滚,你将通过id引用你的交易,对吧?