【问题标题】:MySQL isolation levels in nodejs. Is each query in connection isolated or each pool isolated?nodejs 中的 MySQL 隔离级别。连接中的每个查询是隔离的还是每个池隔离的?
【发布时间】:2018-08-04 19:16:34
【问题描述】:

对于每个会话,我当前的 MySQL 隔离级别是 tx_transaction = REPEATABLE-READ

所以当我在不同的终端运行下面​​的代码时,事务是串行执行的,这意味着在第一个事务提交之前,第二个事务不会启动。

START TRANSACTION;
SELECT *
FROM test
WHERE id = 4 FOR UPDATE;
UPDATE test
SET parent = 98
WHERE id = 4;

那么,如果我在 nodeJS 中实现它,以下哪项会给出与运行两个终端相同的结果?

var mysql      = require('mysql');
var connection = mysql.createConnection({
  host     : 'localhost',
  user     : 'me',
  password : 'secret',
  database : 'my_db'
});

connection.connect();

let query = 
    START TRANSACTION;
    SELECT *
    FROM test
    WHERE id = 4 FOR UPDATE;
    UPDATE test
    SET parent = 98
    WHERE id = 4;

connection.query(query, function (error, results, fields) {
  if (error) throw error;
  console.log('The solution is: ', results[0].solution);
});

connection.query(query, function (error, results, fields) {
  if (error) throw error;
  console.log('The solution is: ', results[0].solution);
});

connection.end();

或使用池

var mysql = require('mysql');
var pool  = mysql.createPool({
  connectionLimit : 10,
  host            : 'example.org',
  user            : 'bob',
  password        : 'secret',
  database        : 'my_db'
});

let query = 
    START TRANSACTION;
    SELECT *
    FROM test
    WHERE id = 4 FOR UPDATE;
    UPDATE test
    SET parent = 98
    WHERE id = 4;

pool.query(query, function (error, results, fields) {
  if (error) throw error;
  console.log('The solution is: ', results[0].solution);
  connection.release();
});

pool.query(query, function (error, results, fields) {
  if (error) throw error;
  console.log('The solution is: ', results[0].solution);
  connection.release();
});

我的第一个猜测是,池将创建单独的连接,并且在同一连接中发送查询与在同一终端中输入查询相同。但是文档在介绍部分说https://github.com/mysqljs/mysql#pooling-connections

您在连接上调用的每个方法都会排队并在 顺序。

我不确定这是什么意思。

另外,如果我使用连接池,我能否 100% 确定并发运行的查询由不同的会话处理?例如,如果第一个查询中没有释放池,那么第二个查询是否总是由另一个会话执行?

【问题讨论】:

    标签: mysql sql node.js acid isolation


    【解决方案1】:

    我做了一些测试,发现Connection Pooling 达到了预期的效果。

    当我只使用连接进行以下操作时

    let pool = mysql.createConnection({
        connectionLimit:10,
        host: 'localhost',
        user: 'root',
        password: 'thflqkek12!',
        database: 'donationether'
    });
    
    connection.beginTransaction(function (err) {
        console.log('first transaction has started');
    
        if (err) {
            console.log(err);
            return;
        }
    
        connection.query(`INSERT INTO users VALUES (null, 0, 'username', 'token')`, function (err, results, fields) {
            if (err) {
                console.log(err);
                return;
            }
    
            setTimeout(function () {
                connection.commit(function (err) {
                    if (err) {
                        console.log(err);
                        return;
                    }
    
                    console.log('first query done');
                    connection.release();
                })
            }, 2000)
        });
    });
    
    connection.beginTransaction(function (err) {
    
        console.log('second transaction has started');
    
        if(err) {
            console.log(err);
            return;
        }
    
        connection.query(`UPDATE users SET username = 'c_username' WHERE username = 'username'`,function (err, results, fields) {
            if(err) {
                console.log(err);
                return;
            }
    
            connection.commit(function (err) {
                if(err) {
                    console.log(err);
                    return;
                }
    
                console.log('second query done');
                connection.release();
            })
        });
    });
    

    它导致以下输出

    first transaction has started
    second transaction has started
    second query done
    first query done
    

    表示第一个连接打开的事务被忽略,第二个事务在此之前完成。但是,当我对以下代码使用连接池时,

    let pool = mysql.createPool({
        connectionLimit:10,
        host: 'localhost',
        user: 'root',
        password: 'thflqkek12!',
        database: 'donationether'
    });
    
    pool.getConnection(function (err, connection) {
        connection.beginTransaction(function (err) {
            console.log('first transaction has started');
    
            if (err) {
                console.log(err);
                return;
            }
    
            connection.query(`INSERT INTO users VALUES (null, 0, 'username', 'token')`, function (err, results, fields) {
                console.log('first query has started');
                if (err) {
                    console.log(err);
                    return;
                }
    
                setTimeout(function () {
                    connection.commit(function (err) {
                        if (err) {
                            console.log(err);
                            return;
                        }
    
                        console.log('first query done');
                        connection.release();
                    });
                }, 2000)
            });
        });
    });
    
    pool.getConnection(function (err, connection) {
        connection.beginTransaction(function (err) {
    
            console.log('second transaction has started');
    
            if(err) {
                console.log(err);
                return;
            }
    
            connection.query(`UPDATE users SET username = 'c_username' WHERE username = 'username'`,function (err, results, fields) {
                console.log('second query has started');
                if(err) {
                    console.log(err);
                    return;
                }
    
                connection.commit(function (err) {
                    if(err) {
                        console.log(err);
                        return;
                    }
    
                    console.log('second query done');
                    connection.release();
                })
            });
        });
    });
    

    输出如下

    first transaction has started
    second transaction has started
    first query has started
    //2seconds delay
    second query has started
    first query done
    second query done
    

    表示第一个事务正在阻止第二个事务执行。

    所以当文档说

    您在连接上调用的每个方法都会排队并按顺序执行

    这意味着它们是按顺序交付到数据库的,但即使在事务下它仍然是异步和并行的。但是,连接池会导致多个连接的实例化,并且不同池连接中的事务的行为与每个事务的预期相同。

    【讨论】:

      猜你喜欢
      • 2015-02-07
      • 2011-07-17
      • 2010-12-04
      • 2016-01-20
      • 1970-01-01
      • 2021-12-23
      • 1970-01-01
      相关资源
      最近更新 更多