Каков правильный способ использования модуля node.js postgresql?

Я пишу приложение node.js на Heroku и используя

Документация использует такой код:

pg.connect(conString, function(err, client) {
  // Use the client to do things here
});

Но, конечно, вам не нужно вызывать pg.connect внутри каждой функции, которая правильно использует базу данных? Я видел , который делает это:

var conString = process.env.DATABASE_URL || "tcp://postgres:[email protected]/postgres";
var client = new pg.Client(conString);
client.connect();
// client is a global so you can use it anywhere now

Я склоняюсь ко второму варианту, так как считаю, что бесплатный экземпляр базы данных для Heroku ограничен одним соединением, но есть ли какие-то недостатки в этом? Должен ли я проверять, все ли подключен мой объект-клиент, прежде чем использовать его?

Ответ 1

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

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

Сервер PostgreSQL может обрабатывать только один запрос за один раз за соединение. Это означает, что если у вас есть 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 module, который делает именно это.

Ответ 2

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

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

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

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:[email protected]:port/database';

const db = pgp(cn); // database instance;

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

Ответ 3

Пул - это путь, по которому можно пойти сейчас. Некоторые вещи вроде этого

const { Pool } = require('pg');

    const pool = new Pool({
      connectionString: DATABASE_URL,
      ssl: false,
      max: 20,
      idleTimeoutMillis: 30000,
      connectionTimeoutMillis: 2000,
    });
    module.exports = {
        query: (text, params) => pool.query(text, params)
      }

его можно использовать как db.query('<BEGIN,COMMIT,ROLLBACK,your query,anything')

Ответ 4

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

Ответ 5

Лучше создать пул 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();

        });
}

});  

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

Ответ 6

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

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'
}

Ответ 7

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

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()