MySQL nodejs 中的隔离级别。连接中的每个查询是独立的还是每个池都是独立的?

MySQL isolation levels in nodejs. Is each query in connection isolated or each pool isolated?

我当前 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

Every method you invoke on a connection is queued and executed in sequence.

我不太确定那是什么意思。

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

我做了一些测试,发现 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

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

所以当文档说

Every method you invoke on a connection is queued and executed in sequence

意味着它们是顺序传递到数据库的,但即使在事务下它仍然是异步和并行的。但是,连接池会导致多个连接的实例化,并且不同池连接内的事务对每个事务的行为都符合预期。