Node Webアプリの永続的なMySQL接続が必要です。問題は、これが1日に数回発生することです。
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コードは機能しません。
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);
});
});
});
私はこれが非常に遅れていることを知っていますが、これに対する解決策を書いたので、もう少し一般的で使いやすいかもしれません。私は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);
});
});
}
};
_
これにより、プールが1回インスタンス化され、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);
}
});
}
_
これは通常のクエリと同じように見えますが、実際にはプールを開き、バックグラウンドでプールから接続を取得します。
@ 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});
});