MySQL事务不会从for循环中停止竞争条件

时间:2013-10-09 22:19:13

标签: mysql sql node.js node-mysql

我在我的应用程序中使用node-mysql。我尝试实施SELECT FOR UPDATE,但我无法让它正常工作。我遇到的问题看起来像下面的代码。下面for循环中的第一个事务没有成功阻止第二个事务。相反,两个事务同时SELECT FOR UPDATE并获得相同的记录。我怎样才能解决这个问题?谢谢!

var testTransaction = function (count) {
  connection.beginTransaction(function(err) {
    if (err) throw err;
    db.query('SELECT * FROM myTable WHERE id = 1 FOR UPDATE', function(err, rows, result) {
      if (err) { 
        connection.rollback(function() {
          throw err;
        });
      }
      connection.query('UPDATE myTable SET myField=? WHERE id=1', (count + 1), function(err, result) {
        if (err) { 
          db.rollback(function() {
            throw err;
          });
        }  
        connection.commit(function(err) {
          if (err) { 
            db.rollback(function() {
              throw err;
            });
          }
          console.log('success!');
        });
      });

    }); 

  });
}

for (var i = 0; i < 2; i++) {
  testTransaction(i);
}

2 个答案:

答案 0 :(得分:0)

node-mysql模块中的方法被编写为异步,因此不会阻止应用程序。如果您没有理由使用循环,那么您只需向函数添加一个回调并嵌套执行:

var testTransaction = function(count, callback) {
  connection.beginTransaction(function (err) {
    if (err) throw err;
    db.query('SELECT * FROM myTable WHERE id = 1 FOR UPDATE', function (err, rows, result) {
      if (err) {
        connection.rollback(function() {
          return callback(err);
        });
      }
      connection.query('UPDATE myTable SET myField=? WHERE id=1', (count + 1), function (err, result) {
        if (err) {
          db.rollback(function() {
            return callback(err);
          });
        }
        connection.commit(function (err) {
          if (err) {
            db.rollback(function() {
              return callback(err);
            });
          }
          callback(null);
          console.log('success!');
        });
      });
    });
  });
};

testTransaction(0, function(err) {
  testTransaction(1, function(err) {
    // both operations have completed
  });
});

如果由于某种原因需要循环异步函数,那么我将查看async库。

答案 1 :(得分:0)

您的问题是您使用相同的连接。

尝试这样的事情:

var mysql      = require('mysql');
function conn() {
    var connection = mysql.createConnection({
        host     : 'localhost',
        user     : 'user',
        password : 'pass',
        database : 'test'
    });
    return connection;
}

var testTransaction = function (connection,count) {
    connection.beginTransaction(function(err) {
        if (err) throw err;
        connection.query('SELECT * FROM table WHERE id = 1 FOR UPDATE', function(err, rows, result) {
            console.log(rows);
            if (err) {
                connection.rollback(function() {
                    throw err;
                });
            }
            connection.query('UPDATE table SET name=? WHERE id=1', (count + 1), function(err, result) {
                if (err) {
                    connection.rollback(function() {
                        throw err;
                    });
                }
                setTimeout(function(){
                    connection.commit(function(err) {
                        if (err) {
                            connection.rollback(function() {
                                throw err;
                            });
                        }
                        console.log('success!');
                    });
                },2000);
            });

        });

    });
}

for (var i = 0; i < 2; i++) {
    testTransaction(conn(),i);
}

请注意,它为每个事务使用不同的连接。

在命令行mysql中,您可以通过打开两个连接来复制类似的东西,在两者中发出start transaction,然后在一个中尝试select ... for update两次(两次都有效)并且一次另一个(等待第一个)。