Как правильно использовать модуль node.js postgresql? - PullRequest
89 голосов
/ 13 декабря 2011

Я пишу приложение node.js на Heroku и использую модуль 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 в любом случае ограничен одним соединением, ноЕсть ли недостатки сделать это таким образом?Нужно ли мне каждый раз проверять, подключен ли мой клиентский объект, прежде чем я его использую?

Ответы [ 6 ]

150 голосов
/ 10 октября 2013

Я автор node-postgres . Во-первых, я извиняюсь, документация не смогла сделать правильный выбор ясным: это моя вина. Я постараюсь улучшить это. Я написал Суть только сейчас, чтобы объяснить это, потому что разговор стал слишком длинным для Твиттера.

Использование pg.connect - это способ пойти в веб-среде.

Сервер PostgreSQL может обрабатывать только 1 запрос за одно соединение. Это означает, что если у вас есть 1 глобальный new pg.Client(), подключенный к вашему Бэкэнд всего вашего приложения ограничен в зависимости от того, насколько быстро Postgres может отвечать на запросы. Это буквально выстроит все в очередь каждый запрос. Да, это асинхронно и все в порядке ... но не так ли а умножить свою пропускную способность в 10 раз? Используйте pg.connect установить pg.defaults.poolSize к чему-то вменяемому (мы делаем 25-100, не уверен правильный номер еще).

new pg.Client для тех случаев, когда вы знаете, что делаете. Когда ты нуждаешься один долгоживущий клиент по какой-то причине или нужно очень осторожно контролировать жизненный цикл. Хороший пример этого при использовании LISTEN/NOTIFY. Слушающий клиент должен быть рядом и подключен и не используется, поэтому он может правильно обрабатывать NOTIFY сообщения. Другой пример был бы при открытии 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 на пользовательский пул клиентов или что-то еще, и вам нужно только изменить вещи в одном месте.

Взгляните на модуль node-pg-query , который делает именно это.

22 голосов
/ 16 мая 2015

Я являюсь автором pg-обещания , который упрощает использование node-postgres через обещания.

В нем рассматриваются вопросы о правильном способеподключение к базе данных и отключение от нее, используя пул соединений, реализованный node-postgres , среди прочего, как автоматические транзакции.

Индивидуальный запрос в pg-prom сводится к тому, что имеет отношение к вашей бизнес-логике:

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;

Вы можете найти много других примеров в учебнике Learn by Example или на домашней странице проекта .

0 голосов
/ 26 ноября 2017

Лучше создать глобальный пул pg, и каждый раз, когда вам нужно выполнить операцию 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();

        });
}

});  

Для более подробной информации, вы можете обратиться к моему сообщению в блоге - Источник

0 голосов
/ 10 августа 2016

Меня заинтересовал очень простой обработчик для этого, поэтому я сделал свой собственный, не усложняя его. Я не питаю иллюзий, что это супер просто, но это может помочь некоторым людям начать. По сути, он подключается, выполняет запросы и обрабатывает ошибки для вас.

function runQuery(queryString, callback) {
  // connect to postgres database
  pg.connect(postgresDatabase.url,function(err,client,done) {
    // if error, stop here
    if (err) {console.error(err); done(); callback(); return;}
    // execute queryString
    client.query(queryString,function(err,result) {
      // if error, stop here
      if (err) {console.error(err+'\nQuery: '+queryString); done(); callback(); return;}
      // callback to close connection
      done();
      // callback with results
      callback(result.rows);
    });
  });
}

Тогда вы бы назвали это так:

runQuery("SELECT * FROM table", function(result) {
  // Whatever you need to do with 'result'
}
0 голосов
/ 02 октября 2015

Вот как я это делаю, вроде «все вышеперечисленное»

Promise = require 'bluebird'
pg = module.exports = require 'pg'

Promise.promisifyAll pg.Client.prototype
Promise.promisifyAll pg.Client
Promise.promisifyAll pg.Connection.prototype
Promise.promisifyAll pg.Connection
Promise.promisifyAll pg.Query.prototype
Promise.promisifyAll pg.Query
Promise.promisifyAll pg

connectionString = process.env.DATABASE_URL

module.exports.queryAsync = (sql, values) ->
  pg.connectAsync connectionString
  .spread (connection, release) ->
    connection.queryAsync sql, values
    .then (result) ->
      console.log result.rows[0]
    .finally ->
      release()
0 голосов
/ 13 декабря 2011

Как видно из документации , оба варианта действительны, поэтому выбирайте, какой вы предпочитаете. Как и вы, я бы выбрал второй вариант.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...