使用mysql和node.js的可序列化事务

我在使用node.js和mysql进行事务时遇到问题。 问题是我的事务不会孤立运行,即使我将隔离级别设置为“可序列化”。

我设置了以下最小的例子来说明我的问题。 我正在使用具有两个columns(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); 

请注意,我正在解除InnoDB表types,因为它支持事务。

我的node.js程序只是读取表A中单行的值,并使用update语句来增加它。 select语句使用FOR UPDATE修饰符来获得该行的locking。 这两个sql语句被封装到一个事务中,并且我在for循环中执行了这些事务中的10个:

 var orm = require("orm"); orm.connect("mysql://root@localhost/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 ... 

解决这个问题的一种方法是为每个事务build立一个新的数据库连接,但是由于性能方面的原因,我不希望这样做。

有人可以解释发生了什么,以及我可以如何将上述变成node.js中事务的工作示例?

好的,我们find了一个使用node-mysql-transaction软件包的解决scheme(见下面的代码)。

 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(); }) }) }) } 
Interesting Posts