2011-05-09 36 views
11

Estoy construyendo una aplicación en node.js usando express y driver node-mysql. Hay un par de casos en mi aplicación cuando necesito hacer una serie de inserciones/actualizaciones de bases de datos. Los quiero en una transacción tal que si falla el segundo o el tercero, los insertos previos se retrotraen completamente.Node.js + MySQL - manejo de transacciones

Actualmente, la forma en que lo hago es tener algún tipo de middleware que hace un START TRANSACTION cuando llega una solicitud. Durante el curso del procesamiento de la solicitud, si se produce un error, detecto este error y hago un ROLLBACK. Si no ocurre ningún error, hago un COMMIT antes de enviar la respuesta al navegador.

Sin embargo, ahora me preocupa que esto no funcione cuando varios usuarios accedan a la aplicación simultáneamente, ya que MySQL realiza una confirmación forzada si otra solicitud intenta comenzar su propia transacción con START TRANSACTION. Actualmente estoy usando solo una instancia de nodo y una sola conexión MySQL para todas las solicitudes.

¿Puede alguien por favor avisarme si mis inquietudes son válidas, y cómo debería obtener soporte de transacciones?

+0

Si tiene la opción, puede valer la pena usar couch/redis/mongo en su lugar, ya que es más fácil de usar con el nodo. Si ya tiene una base de datos MYSQL, continúe usándola. – Raynos

+0

@Raynos AFAIK MongoDb no tiene soporte para transacciones ... – renatoargh

Respuesta

4

Tendrá que crear un grupo de clientes, o de alguna manera asegurarse de que dos páginas diferentes no intercalen comandos en la misma conexión (al menos mientras cualquiera de ellos está en una transacción).

Dado que desea realizar un rollback condicional en función del resultado de un comando anterior, deberá encadenar las llamadas a través de sus callbacks y no depender del comportamiento de cola node-mysql. Esto abrirá una ventana para que entre otra página y ponga en cola una operación en la misma conexión que sugiera.

Puede crear y administrar su propia cola, pero eso terminaría serializando todas las páginas transaccionales (suponiendo que se quede con el modelo de conexión único).

Desde una búsqueda rápida en Google, parece que hay varias agrupaciones node-mysql en github. Sin embargo, después de mirarlos, no parece que te ayuden con tu problema.

1

Me resulta difícil creer que si una sesión por separado ejecuta un START TRANSACTION se comprometan otras transacciones. Eso sería totalmente inseguro, especialmente cuando los datos deben ser revertidos (¿o está "retrotraído"?).

¿Es posible que esté mezclando esto con una misma sesiónSTART TRANSACTION?
Consulte http://dev.mysql.com/doc/refman/5.0/en/implicit-commit.html donde explica que las transacciones no se pueden anidar. Eso, por supuesto, se aplica a la misma sesión , no a la sesión de otro usuario.

Suponiendo que no se haya equivocado con el nivel de aislamiento de su sesión, o el nivel de aislamiento global, entonces las transacciones deberían ser seguras.

En cualquier caso, si desea poner en cola sus transacciones, no sería difícil construir un objeto de cola global en el nodo y encadenar las llamadas (para que uno comience cuando termine otro). Una simple matriz con push y pop debería hacer el truco.

+0

En el contexto de MySQL, una conexión equivale a una 'sesión'. El OP está utilizando una única conexión, por lo que es una única sesión de MySQL compartida en todo el proceso de solicitud. – SystemParadox

+0

@SystemParadox, eso es cierto. Entendí que la pregunta era un problema con conexiones separadas, y cuando el OP dijo que "conexión única" significaba por usuario. – davin

6

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

que implementa un pequeño envoltorio de ganglios MySQL para apoyar las transacciones y múltiples declaraciones. No ha sido probado, y NO está listo para producción ... pero será dentro de unos días.:)

ACTUALIZACIÓN: He probado esta biblioteca bastante bien ahora ... ¡debería estar bien para ir!

5

Dependiendo de qué tan compleja sea su transacción, es posible que se encuentre con un feo agrupamiento al intentar poner sus consultas en cola de Node, lo que podría generar desagradables problemas en el ámbito de las variables.

Lo que puede hacer en su lugar es escribir un procedimiento almacenado y termina por SELECT ing una bandera de éxito/fracaso, a continuación, consulta el procedimiento con node-mysql como lo haría una consulta SELECT. Así es como podría ser el procedimiento almacenado:

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 ; 

Su código Nodo sería algo como esto:

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

Esta es en realidad una forma muy interesante de abordar el problema. Estoy pensando, ¿tal vez preprocesar las consultas en el momento del inicio del servidor y convertir las llamadas al ORM en procedimientos almacenados? Me encantaría tener tus pensamientos sobre la mejor manera de trabajar que si me disparas una nota. Estoy trabajando en un ORM cross-db llamado Waterline. – mikermcneil

0

Sólo una idea: en PostreSQL puede iniciar una transacción y establecer un ID a la misma. Entonces, podrías reutilizar la misma conexión, porque en caso de que necesites comprometer o revertir, te referirás a tu transacción por identificación, ¿verdad?

Cuestiones relacionadas