Каков правильный способ использования модуля 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()