2011-05-09 60 views
11

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

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

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

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

+0

如果您有选择,可以使用couch/redis/mongo代替,因为那里更容易使用节点。如果你已经有一个MYSQL数据库继续使用它。 – Raynos 2011-05-09 22:33:06

+0

@Raynos AFAIK MongoDb不支持事务... – renatoargh 2013-06-18 23:01:07

回答

4

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

由于您想基于先前命令的结果有条件地执行回滚,因此您需要通过回调链接db调用,而不依赖于node-mysql排队行为。这将打开一个窗口,让其他页面进入并按照您的建议在同一连接上排队操作。

您可以创建和管理自己的队列,但最终会序列化所有事务性页面(假设您坚持使用单一连接模型)。

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

1

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

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

假设您没有搞乱会话的隔离级别或全局隔离级别,那么事务应该是安全的。在任何情况下,如果您想对事务进行排队,在节点中构建全局队列对象并链接调用并不困难(所以在另一个完成时启动)。一个简单的数组与推动和流行应该做的伎俩。

+0

在MySQL的上下文中,一个连接等于一个“会话”。 OP使用单个连接,因此它是跨所有请求处理共享的单个MySQL会话。 – SystemParadox 2012-10-16 13:38:23

+0

@SystemParadox,的确如此。我将这个问题理解为单独连接的问题,并且当OP表示“单一连接”时,他/他意味着每个用户。 – davin 2012-10-16 15:20:15

6

退房https://github.com/bminer/node-mysql-queues

我实现了一个小包装为节点的MySQL支持事务和多条语句。它没有经过测试,并没有准备好生产......但它会在几天内完成。:)

UPDATE:我已经测试了这个库很彻底,现在...应该很好去!

5

取决于交易的复杂程度,您可能会遇到一些丑陋的嵌套,试图从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 ... 

    } 
}); 
+0

这实际上是一种解决问题的非常有趣的方式 - 我在想,也许是在服务器启动时预处理查询并将调用转换为ORM存储过程?如果你想给我发一张便条,我很乐意把你的想法变成最好的工作方式。我正在研究一个名为Waterline的cross-db ORM。 – mikermcneil 2012-12-26 12:06:18

0

只是一个想法:在postresql你就可以开始交易和ID设置给它。那么,你可以重复使用相同的连接,因为如果你需要提交或回滚,你将通过id引用你的事务,对吧?