Мой текущий уровень изоляции для 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% уверенным, что одновременно выполняемые запросы обрабатываются разными сеансами? Так, например, если пул не будет выпущен в первом запросе, будет ли второй запрос ВСЕГДА выполняться другим сеансом?
Я провел несколько тестов и понял, что результаты 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
что первая транзакция блокирует выполнение второй транзакции.
Поэтому, когда в документации говорится
Каждый метод, который вы вызываете при подключении, ставится в очередь и выполняется последовательно
Это означало, что они доставляются в базу данных последовательно, но они все равно будут асинхронными и параллельными даже по транзакции. Однако объединение пулов приводит к созданию нескольких соединений, и транзакция в разных пулах ведет себя так, как ожидалось для каждой транзакции.