2014-09-28 35 views
2

我遇到了使用node.js和mysql的事務問題。問題是我的事務不會孤立運行,即使我將隔離級別設置爲「可序列化」。使用mysql和node.js的可序列化事務

我設置了下面的最小示例來舉例說明我的問題。我使用兩個collumns(ID,VAL)的單個表:

CREATE TABLE `A` (
    `id` int(11) unsigned NOT NULL AUTO_INCREMENT, 
    `val` int(11) DEFAULT NULL, 
    PRIMARY KEY (`id`) 
) ENGINE=InnoDB DEFAULT CHARSET=latin1; 

INSERT INTO `A` (`id`, `val`) VALUES (1,0); 

請注意,我unsing InnoDB表類型,因爲它支持事務。

我的node.js程序只是從表A中的單行讀取值,並使用update語句增加它。 select語句使用FOR UPDATE修飾符來獲取行上的鎖。兩個SQL語句被包裹成一個交易,我在執行這些交易的10環:

var orm = require("orm"); 
orm.connect("mysql://[email protected]/test", function (err, db) { 
    db.driver.execQuery("SET GLOBAL tx_isolation='SERIALIZABLE';", function (err, data) { 
     for (var i = 0; i < 10; i++) { 
      db.driver.execQuery("START TRANSACTION;", function (err, data) { 
       db.driver.execQuery("SELECT * FROM A FOR UPDATE;", function (err, data) { 

        var value = data[0].val 
        console.log('reading value: ',value) 

        db.driver.execQuery("UPDATE A SET val="+value+"+1 WHERE id=1", function (err, data) { 
         console.log('writing value: ', value+1) 

         db.driver.execQuery("COMMIT;", function (err, data) {}) 
        }) 
       }) 
      }) 
     } 
    }) 
}) 

我預計運行此代碼後,存儲在表A中的值由10增加。然而,它只是遞增1.

爲了解發生了什麼,我在代碼中添加了打印輸出。我希望看到打印輸出

reading value 0 
writing value 1 
reading value 1 
writing value 2 
... 

但是我得到的打印輸出

reading value 0 
reading value 0 
... 
writing value 1 
writing value 1 
... 

一種方法來解決這個問題是建立交易的每一個新的數據庫連接,但我不想做出於性能原因。

有人可以解釋發生了什麼,以及我可以如何將上述變爲node.js中事務的工作示例?

回答

1

好的,我們找到了一個使用node-mysql-transaction包的解決方案(見下面的代碼)。

var mysql = require('mysql'); 
var transaction = require('node-mysql-transaction'); 

var trCon = transaction({ 
    connection: [mysql.createConnection,{ 
    host  : 'localhost', 
    database : 'test', 
    user  : 'root', 
    password : 'root', 
    }], 
    dynamicConnection: 32, 
    idleConnectionCutoffTime: 1000, 
    timeout:600 
}); 

for(var i=0;i<10;i++) { 

trCon.set(function(err, safeCon){ 

    safeCon.query('SELECT * FROM A FOR UPDATE;',[],function(err,result){ 
    if (err) safeCon.rollback() 

    var val = result[0].val 
    val += 1 

    safeCon.query('UPDATE A SET val='+val,[],function(err,result){ 
     if (err) safeCon.rollback(err) 
     else safeCon.commit(); 
    }) 
    }) 
})  
}