Node.js MySQL, требующий постоянного соединения
Мне нужно постоянное соединение MySQL для моего веб-приложения Node. Проблема в том, что это происходит несколько раз в день:
Error: Connection lost: The server closed the connection.
at Protocol.end (/var/www/n/node_modules/mysql/lib/protocol/Protocol.js:73:13)
at Socket.onend (stream.js:79:10)
at Socket.EventEmitter.emit (events.js:117:20)
at _stream_readable.js:895:16
at process._tickCallback (node.js:415:13)
error: Forever detected script exited with code: 8
error: Forever restarting script for 2 time
info: socket.io started
Вот мой код подключения:
// Yes I know multipleStatements can be dangerous in the wrong hands.
var sql = mysql.createConnection({
host: 'localhost',
user: 'my_username',
password: 'my_password',
database: 'my_database',
multipleStatements: true
});
sql.connect();
function handleDisconnect(connection) {
connection.on('error', function(err) {
if (!err.fatal) {
return;
}
if (err.code !== 'PROTOCOL_CONNECTION_LOST') {
throw err;
}
console.log('Re-connecting lost connection: ' + err.stack);
sql = mysql.createConnection(connection.config);
handleDisconnect(sql);
sql.connect();
});
}
handleDisconnect(sql);
Как вы можете видеть, код handleDisconnect не работает.
Ответы
Ответ 1
Использовать пул соединений mysql. Он снова подключится, когда соединение умрет, и вы получите дополнительное преимущество в том, что сможете одновременно выполнять несколько запросов sql. Если вы не используете пул базы данных, ваше приложение будет блокировать запросы базы данных, ожидая завершения текущих запросов к базе данных.
Обычно я определяю модуль базы данных, где я сохраняю свои запросы отдельно от своих маршрутов. Это выглядит примерно так...
var mysql = require('mysql');
var pool = mysql.createPool({
host : 'example.org',
user : 'bob',
password : 'secret'
});
exports.getUsers = function(callback) {
pool.getConnection(function(err, connection) {
if(err) {
console.log(err);
callback(true);
return;
}
var sql = "SELECT id,name FROM users";
connection.query(sql, [], function(err, results) {
connection.release(); // always put connection back in pool after last query
if(err) {
console.log(err);
callback(true);
return;
}
callback(false, results);
});
});
});
Ответ 2
Я знаю, что это супер задерживается, но я написал для этого решение, которое, я думаю, может быть более общим и полезным. Я написал приложение, полностью зависящее от connection.query()
, и переключение на пул нарушило эти вызовы.
Здесь мое решение:
var mysql = require('mysql');
var pool = mysql.createPool({
host : 'localhost',
user : 'user',
password : 'secret',
database : 'test',
port : 3306
});
module.exports = {
query: function(){
var sql_args = [];
var args = [];
for(var i=0; i<arguments.length; i++){
args.push(arguments[i]);
}
var callback = args[args.length-1]; //last arg is callback
pool.getConnection(function(err, connection) {
if(err) {
console.log(err);
return callback(err);
}
if(args.length > 2){
sql_args = args[1];
}
connection.query(args[0], sql_args, function(err, results) {
connection.release(); // always put connection back in pool after last query
if(err){
console.log(err);
return callback(err);
}
callback(null, results);
});
});
}
};
Это создает экземпляр пула один раз, затем экспортирует метод с именем query
. Теперь, когда connection.query()
вызывается в любом месте, он вызывает этот метод, который сначала захватывает соединение из пула, а затем передает аргументы в соединение. Он имеет дополнительный эффект захвата обратного вызова в первую очередь, поэтому он может отменить любые ошибки в захвате соединения из пула.
Чтобы использовать это, просто попросите его в качестве модуля вместо mysql. Пример:
var connection = require('../middleware/db');
function get_active_sessions(){
connection.query('Select * from `sessions` where `Active`=1 and Expires>?;', [~~(new Date()/1000)], function(err, results){
if(err){
console.log(err);
}
else{
console.log(results);
}
});
}
Это выглядит так же, как обычный запрос, но фактически открывает пул и захватывает соединение из пула в фоновом режиме.
Ответ 3
В ответ на @gladsocc вопрос:
Есть ли способ использовать пулы без реорганизации всего? у меня есть десятки SQL-запросов в приложении.
Это то, что я закончил строительство. Это оболочка для функции запроса. Он захватит соединение, выполнит запрос и отпустит соединение.
var pool = mysql.createPool(config.db);
exports.connection = {
query: function () {
var queryArgs = Array.prototype.slice.call(arguments),
events = [],
eventNameIndex = {};
pool.getConnection(function (err, conn) {
if (err) {
if (eventNameIndex.error) {
eventNameIndex.error();
}
}
if (conn) {
var q = conn.query.apply(conn, queryArgs);
q.on('end', function () {
conn.release();
});
events.forEach(function (args) {
q.on.apply(q, args);
});
}
});
return {
on: function (eventName, callback) {
events.push(Array.prototype.slice.call(arguments));
eventNameIndex[eventName] = callback;
return this;
}
};
}
};
И я использую его, как обычно.
db.connection.query("SELECT * FROM `table` WHERE `id` = ? ", row_id)
.on('result', function (row) {
setData(row);
})
.on('error', function (err) {
callback({error: true, err: err});
});