私は、MySQLを最も効率的な方法で使用するためにアプリケーションを構成する方法を見つけようとしています。 node-mysqlモジュールを使用しています。ここの他のスレッドは接続プーリングを使用することを提案したので、小さなモジュールmysql.jsをセットアップしました
var mysql = require('mysql');
var pool = mysql.createPool({
Host : 'localhost',
user : 'root',
password : 'root',
database : 'guess'
});
exports.pool = pool;
これで、mysqlを照会するたびに、このモジュールが必要になり、次にデータベースを照会します
var mysql = require('../db/mysql').pool;
var test = function(req, res) {
mysql.getConnection(function(err, conn){
conn.query("select * from users", function(err, rows) {
res.json(rows);
})
})
}
これは良いアプローチですか?メインのapp.jsスクリプトですべてが行われる非常に単純な接続以外に、mysql接続の使用例をあまり見つけることができなかったので、慣習/ベストプラクティスが何であるかは本当にわかりません。
各クエリの後に必ずconnection.end()を使用する必要がありますか?どこかで忘れたらどうしますか?
Mysqlモジュールのexports部分を書き直して接続だけを返すようにするには、毎回getConnection()を書く必要はありませんか?
それは良いアプローチです。
接続を取得するだけの場合は、プールがあるモジュールに次のコードを追加します。
var getConnection = function(callback) {
pool.getConnection(function(err, connection) {
callback(err, connection);
});
};
module.exports = getConnection;
それでも、毎回getConnectionを記述する必要があります。ただし、最初に取得したときにモジュールに接続を保存できます。
接続の使用が終了したら、忘れずに接続を終了してください。
connection.release();
このラッパーは便利です:)
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});
});
私はこの基本クラス接続をmysqlで使用しています:
「base.js」
var mysql = require("mysql");
var pool = mysql.createPool({
connectionLimit : 10,
Host: Config.appSettings().database.Host,
user: Config.appSettings().database.username,
password: Config.appSettings().database.password,
database: Config.appSettings().database.database
});
var DB = (function () {
function _query(query, params, callback) {
pool.getConnection(function (err, connection) {
if (err) {
connection.release();
callback(null, err);
throw err;
}
connection.query(query, params, function (err, rows) {
connection.release();
if (!err) {
callback(rows);
}
else {
callback(null, err);
}
});
connection.on('error', function (err) {
connection.release();
callback(null, err);
throw err;
});
});
};
return {
query: _query
};
})();
module.exports = DB;
次のように使用します。
var DB = require('../dal/base.js');
DB.query("select * from tasks", null, function (data, error) {
callback(data, error);
});
可能であれば、pool.getConnection()
の使用は避けてください。 pool.getConnection()
を呼び出す場合、接続の使用が終了したらmustconnection.release()
を呼び出します。そうしないと、接続制限に達すると、接続がプールに返されるまでアプリケーションが永久に待機し続けます。
単純なクエリには、pool.query()
を使用できます。この省略表現は、エラー状態であってもconnection.release()
を自動的に呼び出します。
function doSomething(cb) {
pool.query('SELECT 2*2 "value"', (ex, rows) => {
if (ex) {
cb(ex);
} else {
cb(null, rows[0].value);
}
});
}
ただし、場合によってはpool.getConnection()
を使用する必要があります。これらのケースは次のとおりです。
pool.getConnection()
を使用する必要がある場合は、以下のようなパターンを使用してconnection.release()
を呼び出してください。
function doSomething(cb) {
pool.getConnection((ex, connection) => {
if (ex) {
cb(ex);
} else {
// Ensure that any call to cb releases the connection
// by wrapping it.
cb = (cb => {
return function () {
connection.release();
cb.apply(this, arguments);
};
})(cb);
connection.beginTransaction(ex => {
if (ex) {
cb(ex);
} else {
connection.query('INSERT INTO table1 ("value") VALUES (\'my value\');', ex => {
if (ex) {
cb(ex);
} else {
connection.query('INSERT INTO table2 ("value") VALUES (\'my other value\')', ex => {
if (ex) {
cb(ex);
} else {
connection.commit(ex => {
cb(ex);
});
}
});
}
});
}
});
}
});
}
個人的にはPromise
sとuseAsync()
パターンを使用することを好みます。このパターンとasync
/await
を組み合わせると、字句スコープがrelease()
の自動呼び出しに変わるため、.release()
接続を誤って忘れることが非常に難しくなります。
async function usePooledConnectionAsync(actionAsync) {
const connection = await new Promise((resolve, reject) => {
pool.getConnection((ex, connection) => {
if (ex) {
reject(ex);
} else {
resolve(connection);
}
});
});
try {
return await actionAsync(connection);
} finally {
connection.release();
}
}
async function doSomethingElse() {
// Usage example:
const result = await usePooledConnectionAsync(async connection => {
const rows = await new Promise((resolve, reject) => {
connection.query('SELECT 2*4 "value"', (ex, rows) => {
if (ex) {
reject(ex);
} else {
resolve(rows);
}
});
});
return rows[0].value;
});
console.log(`result=${result}`);
}
接続が完了したら、connection.release()
を呼び出すだけで、接続はプールに戻り、他の人が再び使用できるようになります。
var mysql = require('mysql');
var pool = mysql.createPool(...);
pool.getConnection(function(err, connection) {
// Use the connection
connection.query('SELECT something FROM sometable', function (error, results, fields) {
// And done with the connection.
connection.release();
// Handle error after the release.
if (error) throw error;
// Don't use the connection here, it has been returned to the pool.
});
});
接続を閉じてプールから削除する場合は、代わりにconnection.destroy()
を使用します。プールは、次に接続が必要になったときに新しい接続を作成します。
標準のmysql.createPool()を使用して、接続はプールによって遅延的に作成されます。最大100の接続を許可するようにプールを構成し、同時に5つしか使用しない場合、5つの接続のみが作成されます。ただし、500個の接続を設定し、500個すべてを使用する場合、アイドル状態であっても、プロセス中は開いたままになります!
これは、MySQLサーバーのmax_connectionsが510の場合、MySQLサーバーがそれらを閉じる(wait_timeoutの設定に依存する)か、アプリケーションが閉じるまで、システムで使用できるmySQL接続は10のみです。それらを解放する唯一の方法は、プールインスタンスを介して接続を手動で閉じるか、プールを閉じることです。
mysql-connection-pool-managerモジュールは、この問題を修正し、負荷に応じて接続数を自動的にスケーリングするために作成されました。アクティビティがなかった場合、非アクティブな接続は閉じられ、アイドル接続プールは最終的に閉じられます。
// Load modules
const PoolManager = require('mysql-connection-pool-manager');
// Options
const options = {
...example settings
}
// Initialising the instance
const mySQL = PoolManager(options);
// Accessing mySQL directly
var connection = mySQL.raw.createConnection({
Host : 'localhost',
user : 'me',
password : 'secret',
database : 'my_db'
});
// Initialising connection
connection.connect();
// Performing query
connection.query('SELECT 1 + 1 AS solution', function (error, results, fields) {
if (error) throw error;
console.log('The solution is: ', results[0].solution);
});
// Ending connection
connection.end();
参照: https://www.npmjs.com/package/mysql-connection-pool-manager