Herokuでnode.jsアプリを作成し、 pgモジュール を使用しています。データベースを照会する必要のある各要求に対してクライアントオブジェクトを取得する「正しい」方法がわかりません。
ドキュメントでは、次のようなコードを使用しています。
pg.connect(conString, function(err, client) {
// Use the client to do things here
});
ただし、データベースを使用するすべての関数内でpg.connect
を呼び出す必要はありません。 他のコード を見たことがあります:
var conString = process.env.DATABASE_URL || "tcp://postgres:1234@localhost/postgres";
var client = new pg.Client(conString);
client.connect();
// client is a global so you can use it anywhere now
とにかく、Herokuの無料のデータベースインスタンスは1つの接続に限定されると考えているため、2番目のオプションに傾いていますが、この方法で行うことには欠点がありますか?クライアントオブジェクトを使用する前に毎回接続されているかどうかを確認する必要がありますか?
私は node-postgres の著者です。まず、ドキュメントが正しいオプションを明確にできなかったことをおaびします。それが私のせいです。私はそれを改善しようとします。 会話 がTwitterにとって長すぎたため、これを説明するために a Gist を書きました。
_
pg.connect
_を使用することは、Web環境で進む方法です。PostgreSQLサーバーは、接続ごとに一度に1つのクエリしか処理できません。つまり、1つのグローバル
new pg.Client()
がバックエンドに接続されている場合、postgresがクエリに応答する速度に基づいて、アプリ全体がボトルネックになります。文字通りすべてを並べ、各クエリをキューに入れます。ええ、それは非同期ですので、それは大丈夫です...しかし、あなたはむしろあなたのスループットを10倍に倍増しませんか? _pg.connect
_を使用して、_pg.defaults.poolSize
_を正気なものに設定します(25-100を実行しますが、正しい番号はまだわかりません)。_
new pg.Client
_は、自分が何をしているかを知っている場合に使用します。何らかの理由で単一の長寿命クライアントが必要な場合、またはライフサイクルを非常に慎重に制御する必要がある場合。この良い例は、_LISTEN/NOTIFY
_を使用する場合です。リスニングクライアントは、NOTIFY
メッセージを適切に処理できるように、共有されずに接続されている必要があります。他の例は、ハングしたものを殺すために1回限りのクライアントを開くとき、またはコマンドラインスクリプトであるでしょう。
非常に役立つことの1つは、アプリ内のデータベースへのすべてのアクセスを1つのファイルに集中化することです。 _pg.connect
_の呼び出しや新しいクライアントを散らかさないでください。次のような_db.js
_のようなファイルがあります。
_module.exports = {
query: function(text, values, cb) {
pg.connect(function(err, client, done) {
client.query(text, values, function(err, result) {
done();
cb(err, result);
})
});
}
}
_
これにより、実装を_pg.connect
_からクライアントのカスタムプールなどに変更することができ、1か所で変更するだけで済みます。
node-pg-queryモジュール を見てください。
私は pg-promise の作成者です。これにより、promiseによる node-postgres の使用が簡単になります。
node-postgres によって実装された接続プールを使用して、自動トランザクションなどのように、データベースへの適切な接続および切断方法に関する問題に対処します。
pg-promise の個々のリクエストは、ビジネスロジックに関連するものだけに要約されます。
db.any('SELECT * FROM users WHERE status = $1', ['active'])
.then(data => {
console.log('DATA:', data);
})
.catch(error => {
console.log('ERROR:', error);
});
つまり、次のようにグローバルに一度だけ接続を設定するため、クエリを実行するときに接続ロジックを扱う必要はありません。
const pgp = require('pg-promise')(/*options*/);
const cn = {
Host: 'localhost', // server name or IP address;
port: 5432,
database: 'myDatabase',
user: 'myUser',
password: 'myPassword'
};
// alternative:
// const cn = 'postgres://username:password@Host:port/database';
const db = pgp(cn); // database instance;
例で学ぶ チュートリアル、または プロジェクトのホームページ でさらに多くの例を見つけることができます。
documentation からわかるように、両方のオプションが有効なので、どちらを選択してもかまいません。あなたのように、私は2番目の選択肢に行きます。
Pgプールをグローバルに作成し、db操作を行う必要があるたびにクライアントを使用してから、プールにリリースすることをお勧めします。すべてのdb操作が完了したら、pool.end()
を使用してプールを終了します
サンプルコード-
let pool = new pg.Pool(dbConfig);
pool.connect(function(err, client, done) {
if (err) {
console.error('Error connecting to pg server' + err.stack);
callback(err);
} else {
console.log('Connection established with pg db server');
client.query("select * from employee", (err, res) => {
if (err) {
console.error('Error executing query on pg db' + err.stack);
callback(err);
} else {
console.log('Got query results : ' + res.rows.length);
async.each(res.rows, function(empRecord) {
console.log(empRecord.name);
});
}
client.release();
});
}
});
詳細については、私のブログ投稿- Source を参照してください。