node.js postgresql 모듈을 사용하는 적절한 방법은 무엇입니까?


95

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의 무료 데이터베이스 인스턴스가 어쨌든 하나의 연결로 제한되어 있다고 믿기 때문에 두 번째 옵션으로 기울고 있지만 이렇게하는 데 단점이 있습니까? 클라이언트 개체를 사용하기 전에 항상 연결되어 있는지 확인해야합니까?

답변:


158

저는 node-postgres 의 저자입니다 . 첫째, 문서가 올바른 옵션을 명확하게하지 못해 죄송합니다. 그게 내 잘못입니다. 나는 그것을 개선하려고 노력할 것입니다. 트위터에 비해 대화 가 너무 길어 졌기 때문에 이것을 설명하기 위해 방금 요점을 썼습니다 .

사용 pg.connect은 웹 환경 으로 이동하는 방법 입니다.

PostgreSQL 서버는 연결 당 한 번에 하나의 쿼리 만 처리 할 수 ​​있습니다. 즉 new pg.Client(), 백엔드에 1 개의 글로벌이 연결되어 있으면 postgres가 쿼리에 응답 할 수있는 속도에 따라 전체 앱에 병목 현상이 발생합니다. 말 그대로 모든 것을 정렬하여 각 쿼리를 대기열에 넣습니다. 예, 비동기이므로 괜찮습니다 ...하지만 처리량에 10 배를 곱하지 않겠습니까? pg.connect set the pg.defaults.poolSize를 제정신으로 사용하십시오 (우리는 25-100을 수행하지만 올바른 숫자는 아직 확실하지 않습니다).

new pg.Client당신이 무엇을하고 있는지 알 때입니다. 어떤 이유로 한 명의 장수 클라이언트가 필요하거나 수명주기를 매우 신중하게 제어해야하는 경우. 이에 대한 좋은 예는 LISTEN/NOTIFY. 청취 클라이언트는 NOTIFY메시지를 적절하게 처리 할 수 ​​있도록 주변에 있고 연결되어 있어야하며 공유되지 않아야 합니다. 다른 예는 일회성 클라이언트를 열어 정지 된 항목이나 명령 줄 스크립트를 종료하는 경우입니다.

한 가지 매우 유용한 것은 앱의 데이터베이스에 대한 모든 액세스를 하나의 파일로 중앙 집중화하는 것입니다. 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 모듈 을 살펴보십시오 .


2
죄송합니다. 저는 DBMS를 처음 접했고 여전히 이것을 이해하는 데 문제가 있습니다. "litter pg.connect"호출을 원하지 않는 이유는 무엇입니까? 단순성 때문입니까 아니면 성능상의 이유입니까? 예를 들어, 기본 앱에있는 각 경로에서 pg.connect를 한 번씩 호출합니다 (모두 동일한 conString 사용). 괜찮아? 직관적으로 호출 할 때마다 동일한 db에 새로운 연결을 만드는 것처럼 느껴지지만 (원하지 않는) 내부적으로 풀링 된 연결을 사용합니까? 감사.
user1164937

대박. 요청 당 하나가 아닌 쿼리 당 하나의 연결을 사용하는 이유는 무엇입니까? 요청 내 여러 쿼리에서 연결을 공유하는 적절한 방법을 찾고 있었고 여기에서 답변을 찾기 전에 res.locals를 고려했습니다.
조 라플란드

2
아, 기다려. 여기에있는 솔루션이 거래를 지원하지 않는 것 같습니다.
조 라플란드

이것은 github에 영구 링크되어야합니다.
Ryan Willis

1
pg.connect는 node-postgres 일명 pg의 v7 이후 제거되었습니다. stackoverflow.com/questions/45174120/pg-connect-not-a-function
Colin D

24

나는 promise 를 통해 node-postgres 의 사용을 단순화하는 pg-promise 의 저자입니다 .

자동화 된 트랜잭션과 같이 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;

Learn by Example 자습서 또는 프로젝트의 홈 페이지 에서 더 많은 예제를 찾을 수 있습니다 .


안녕하세요, Heroku는 SSL 연결 만 허용합니다. 에서 pg이 지정됩니다 pg.defaults.ssl = true;. 에서 어떻게합니까 pg-promise?
ocram

@ocram github.com/vitaly-t/pg-promise/wiki/… 또는 연결 매개 변수 내에서 SSL을 지정할 수 있습니다. github.com/vitaly-t/pg-promise/wiki/Connection-Syntax
vitaly-t

저는 자바 스크립트, promises, postgres 등의 대부분에 익숙하지 않으며 이것이 바로 제가 필요한 것입니다. 감사합니다!!
Ryan Rodemoyer 2016 년

1
난 그냥 수행하여이 작업을 얻었다 @ocrampgp.pg.defaults.ssl = true;
CharlieC

이것은 postgres에 여러 쿼리 요청을 할 때 자동으로 postgres 처리량을 향상시키기 위해 여러 연결을 생성합니까?
sundar

5

수영장은 이제 갈 길입니다.

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


1

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

        });
}

});  

자세한 내용은 내 블로그 게시물- 출처를 참조하세요.


0

문서 에서 알 수 있듯이 두 옵션 모두 유효하므로 원하는 것을 선택하십시오. 당신으로서 나는 두 번째 선택을 할 것입니다.


연결이 끊어지면 다시 연결하는 것은 어떻습니까? 자동으로 수행됩니까? 오류 처리에 대한 위키 페이지는 ... empty github.com/brianc/node-postgres/wiki/Error-handling
alltom

나는 별도로 요청했습니다 : stackoverflow.com/questions/15619456/...
alltom

-1

나는 이것에 대한 매우 간단한 핸들러에 관심이 있었기 때문에 복잡하게 만들지 않고 직접 만들었습니다. 나는 그것이 매우 기본적이라고 착각하지 않지만 일부 사람들이 시작하는 데 도움이 될 수 있습니다. 기본적으로 연결하고 쿼리를 실행하고 오류를 처리합니다.

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

이것은 풀에 대한 연결을 해제하지도 않습니다. 그것은 풀을 정말 빨리 고갈시킬 것입니다. node-postgres페이지 의 기본 예가 이것보다 낫습니다.
vitaly-t 2013-08-14

-2

제가하는 방법은 "위의 모든 접근 방식"입니다.

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

1
따라서 연결 관리, 트랜잭션 지원 및 작업 지원이 필요하지 않습니다. 그렇다면 요점은 무엇입니까?
vitaly-t

1
어느 언어입니까? 커피? berk
caub jul. 162016-07-16
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.