2011-05-09 8 views
11

express 및 node-mysql 드라이버를 사용하여 node.js에 응용 프로그램을 빌드하고 있습니다. 일련의 데이터베이스 삽입/업데이트를해야 할 때 몇 가지 경우가 있습니다. 두 번째 또는 세 번째 트랜잭션이 실패하면 이전의 트랜잭션이 완전히 롤백되도록 트랜잭션에서 처리하기를 원합니다.Node.js + MySQL - 트랜잭션 처리

현재 내가 수행하는 방식은 요청이 도착하면 START TRANSACTION을 수행하는 일종의 미들웨어를 갖는 것입니다. 요청을 처리하는 과정에서 오류가 발생하면이 오류를 catch하고 ROLLBACK을 수행합니다. 오류가 발생하지 않으면 브라우저에 응답을 보내기 전에 COMMIT을 수행합니다.

그러나 다른 사용자가 START TRANSACTION으로 자신의 트랜잭션을 시작하려고하면 MySQL이 강제 커밋을 수행하므로 여러 사용자가 동시에 응용 프로그램에 액세스 할 때이 기능이 작동하지 않을까 우려됩니다. 나는 현재 노드의 단일 인스턴스와 모든 요청에 ​​대해 단일 MySQL 연결 만 사용하고 있습니다.

내 관심사가 유효한 경우 누군가가 조언을 해주고 거래 지원은 어떻게 받아 들여야합니까?

+0

옵션이있는 경우 노드와 함께 사용하기 쉽기 때문에 couch/redis/mongo를 대신 사용하는 것이 좋습니다. 이미 MYSQL 데이터베이스를 가지고 있다면 계속 사용하십시오. – Raynos

+0

@Raynos AFAIK MongoDb는 트랜잭션을 지원하지 않습니다 ... – renatoargh

답변

4

클라이언트 풀을 생성하거나 다른 방법으로 두 개의 다른 페이지가 동일한 연결에서 명령을 산재시키지 않도록해야합니다 (적어도 트랜잭션에있는 동안).

이전 명령의 결과에 따라 조건부로 롤백을 수행하려면 node-mysql 대기열 동작에 의존하지 않고 콜백을 통해 db 호출을 함께 연결해야합니다. 그러면 다른 페이지가 들어 와서 제안한 것과 동일한 연결에서 작업을 큐에 넣을 창이 열립니다.

자신 만의 큐를 생성하고 관리 할 수는 있지만, 결국 모든 트랜잭션 페이지를 직렬화하게됩니다 (단일 연결 모델을 사용한다고 가정 할 때).

빠른 인터넷 검색에서 github에 여러 노드 -mysql 풀이있는 것처럼 보입니다. 그들을보고 난 후에, 그들은 당신의 문제에 도움이되는 것처럼 보이지 않습니다.

1

별도의 세션이 다른 트랜잭션이 커밋 된 START TRANSACTION을 실행하면 믿을 수 없습니다. 특히 데이터를 롤백해야 할 때 (또는 "롤백"할 때) 특히 위험 할 수 있습니다.

동일한 세션을 동일한 세션에 넣을 수 있습니까?START TRANSACTION?
http://dev.mysql.com/doc/refman/5.0/en/implicit-commit.html에서 트랜잭션을 중첩 할 수 없다고 설명합니다. 물론 이것은 동일한 세션에 적용되며 다른 사용자의 세션에는 적용되지 않습니다.

세션의 격리 수준 또는 전역 격리 수준을 엉망으로 처리하지 않았다고 가정하면 트랜잭션은 안전해야합니다.

어떤 경우에도 트랜잭션을 대기열에 넣고 싶으면 노드에 글로벌 대기열 객체를 작성하고 호출을 연결하기가 어렵지 않습니다 (다른 하나가 완료되면 하나가 시작되도록). 푸시와 팝이있는 간단한 배열이 트릭을 수행해야합니다.

+0

MySQL 컨텍스트에서 하나의 연결은 '세션'과 같습니다. OP는 단일 연결을 사용하므로 모든 요청 처리에서 공유되는 단일 MySQL 세션입니다. – SystemParadox

+0

@ SystemParadox 사실입니다. 나는이 질문이 별도의 연결에 문제가되는 것을 이해했으며, OP가 "단일 연결"이라고 말하면 사용자 당 의미가 있다고 말했다. – davin

6

체크 아웃

https://github.com/bminer/node-mysql-queues 나는 노드 MySQL을 지원하기 위해 거래 및 여러 문에 약간의 래퍼를 구현했습니다. 그것은 테스트되지 않았고 생산 준비가되어 있지 않습니다 ...하지만 며칠 내에있을 것입니다.:)

업데이트 : 나는이 라이브러리를 꽤 철저하게 테스트했다. 잘해야한다.

5

트랜잭션의 복잡성에 따라 일부 추악한 중첩이 발생하여 노드에서 쿼리를 대기열에 넣으려고하면 추악한 변수 범위 지정 문제가 발생할 수 있습니다.

대신 수행 할 수있는 작업은 저장 프로 시저를 작성하고 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 ... 

    } 
}); 
+0

이것은 실제로 문제에 접근하는 매우 흥미로운 방법입니다. 서버 시작 시간에 쿼리를 사전 처리하고 ORM에 대한 호출을 저장 프로 시저로 변환 할 생각입니다. 네가 나에게 메모를 쏘는다면 일하는 가장 좋은 방법에 대한 생각을하고 싶다. 저는 워터 라인 (Waterline)이라는 크로스 DB ORM에서 일하고 있습니다. – mikermcneil

0

그냥 생각 : 당신이 트랜잭션을 시작하고에 ID를 설정할 수 있습니다 postresql에. 그러면 커밋이나 롤백이 필요할 경우 ID로 트랜잭션을 참조하기 때문에 동일한 연결을 다시 사용할 수 있습니다.

관련 문제