【问题标题】:Serializable transactions using mysql and node.js使用 mysql 和 node.js 的可序列化事务
【发布时间】:2014-11-22 21:56:29
【问题描述】:

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

我设置了以下最小示例来举例说明我的问题。我正在使用带有两个列(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 表类型,因为它支持事务。

我的 node.js 程序只是从表 A 中的单行读取值,并使用更新语句递增它。 select 语句使用 FOR UPDATE 修饰符来获得对行的锁定。两条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
...

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

有人可以解释发生了什么,以及如何将上述内容更改为 node.js 中事务的工作示例吗?

【问题讨论】:

    标签: mysql node.js transactions serializable isolation


    【解决方案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();
        })
      })
    })    
    }
    

    【讨论】:

      猜你喜欢
      • 2015-01-17
      • 1970-01-01
      • 2013-03-23
      • 2023-04-01
      • 1970-01-01
      • 2010-11-26
      • 2017-11-26
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多