Cách thích hợp để sử dụng mô-đun node.js postgresql là gì?


95

Tôi đang viết một ứng dụng node.js trên Heroku và sử dụng mô-đun pg . Tôi không thể tìm ra cách "đúng" để lấy một đối tượng khách cho mỗi yêu cầu mà tôi cần truy vấn cơ sở dữ liệu.

Tài liệu sử dụng mã như sau:

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

Nhưng chắc chắn bạn không cần phải gọi pg.connectbên trong mọi hàm có sử dụng cơ sở dữ liệu đúng không? Tôi đã thấy mã khác thực hiện điều này:

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

Tôi đang nghiêng về tùy chọn thứ hai vì tôi tin rằng phiên bản cơ sở dữ liệu miễn phí cho Heroku dù sao cũng bị giới hạn ở một kết nối, nhưng có bất kỳ hạn chế nào khi thực hiện theo cách này không? Tôi có cần kiểm tra xem đối tượng khách hàng của mình có còn được kết nối không trước khi sử dụng?

Câu trả lời:


158

Tôi là tác giả của node-postgres . Đầu tiên, tôi xin lỗi vì tài liệu đã không đưa ra lựa chọn phù hợp rõ ràng: đó là lỗi của tôi. Tôi sẽ cố gắng cải thiện nó. Tôi đã viết một Gist ngay bây giờ để giải thích điều này vì cuộc trò chuyện đã quá dài đối với Twitter.

Sử dụng pg.connectcách để đi trong môi trường web.

Máy chủ PostgreSQL chỉ có thể xử lý 1 truy vấn tại một thời điểm trên mỗi kết nối. Điều đó có nghĩa là nếu bạn có 1 toàn cầu new pg.Client()được kết nối với chương trình phụ trợ của mình, toàn bộ ứng dụng của bạn sẽ bị tắc nghẽn dựa trên tốc độ các postgres có thể phản hồi các truy vấn. Theo nghĩa đen, nó sẽ xếp hàng mọi thứ, xếp hàng mỗi truy vấn. Vâng, nó không đồng bộ và vì vậy không sao cả ... nhưng bạn có muốn nhân thông lượng của mình lên 10 lần không? Sử dụng pg.connect đặt thành pg.defaults.poolSizemột cái gì đó lành mạnh (chúng tôi làm 25-100, không chắc chắn là số đúng).

new pg.Clientlà khi bạn biết mình đang làm gì. Khi bạn cần một khách hàng tồn tại lâu dài vì lý do nào đó hoặc cần kiểm soát rất cẩn thận vòng đời. Một ví dụ điển hình về điều này là khi sử dụng LISTEN/NOTIFY. Ứng dụng khách lắng nghe cần ở xung quanh và được kết nối và không được chia sẻ để nó có thể xử lý NOTIFYcác thông điệp một cách chính xác . Ví dụ khác sẽ là khi mở một ứng dụng khách để giết một số thứ bị treo hoặc trong các tập lệnh dòng lệnh.

Một điều rất hữu ích là tập trung tất cả quyền truy cập vào cơ sở dữ liệu trong ứng dụng của bạn vào một tệp. Đừng xả rác pg.connecttrong suốt cuộc gọi hoặc khách hàng mới. Có một tệp giống db.jsnhư thế này:

module.exports = {
   query: function(text, values, cb) {
      pg.connect(function(err, client, done) {
        client.query(text, values, function(err, result) {
          done();
          cb(err, result);
        })
      });
   }
}

Bằng cách này, bạn có thể thay đổi việc triển khai của mình từ pg.connectmột nhóm khách hàng tùy chỉnh hoặc bất cứ thứ gì và chỉ phải thay đổi mọi thứ ở một nơi.

Hãy xem mô-đun node-pg-query thực hiện điều này.


2
Xin lỗi, tôi còn khá mới với DBMS và tôi vẫn chưa hiểu điều này, nhưng tại sao chúng tôi không muốn gọi "pg.connect"? Đó là vì đơn giản hay vì lý do hiệu suất? Ví dụ: tôi gọi pg.connect một lần trong mỗi tuyến đường tôi có trong ứng dụng cơ bản của mình (tất cả đều có cùng một chuỗi con). Điều này có ổn không? Theo trực giác, có cảm giác như nó đang tạo một kết nối mới với cùng một db bất cứ khi nào tôi gọi nó (điều mà tôi không muốn), nhưng liệu nó có sử dụng các kết nối tổng hợp bên trong không? Cảm ơn.
dùng1164937

Tuyệt vời. Tại sao bạn lại sử dụng một kết nối cho mỗi truy vấn thay vì một kết nối cho mỗi yêu cầu? Tôi đã tìm kiếm một cách thích hợp để chia sẻ kết nối qua nhiều truy vấn trong một yêu cầu và đã xem xét res.locals trước khi tìm thấy câu trả lời của bạn ở đây.
Joe Lapp

2
Ồ, chờ đã. Có vẻ như giải pháp của bạn ở đây sẽ không hỗ trợ giao dịch.
Joe Lapp,

Điều này sẽ được liên kết cố định với github.
Ryan Willis

1
Lưu ý rằng pg.connect đã bị xóa bài v7 của node-postgres hay còn gọi là pg. Xem stackoverflow.com/questions/45174120/pg-connect-not-a- Chức năng
Colin D

23

Tôi là tác giả của pg-promise , đơn giản hóa việc sử dụng node-postgres thông qua các hứa hẹn.

Nó giải quyết các vấn đề về cách kết nối phù hợp và ngắt kết nối với cơ sở dữ liệu, sử dụng nhóm kết nối được thực hiện bởi node-postgres , trong số những thứ khác, như các giao dịch tự động.

Một yêu cầu cá nhân trong pg-promise chỉ tóm tắt những gì liên quan đến logic kinh doanh của bạn:

db.any('SELECT * FROM users WHERE status = $1', ['active'])
    .then(data => {
        console.log('DATA:', data);
    })
    .catch(error => {
        console.log('ERROR:', error);
    });

tức là bạn không cần phải xử lý logic kết nối khi thực hiện các truy vấn, vì bạn chỉ thiết lập kết nối một lần, trên toàn cầu, như thế này:

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;

Bạn có thể tìm thấy nhiều ví dụ khác trong hướng dẫn Tìm hiểu bằng ví dụ hoặc trên trang chủ của dự án .


Xin chào, Heroku chỉ chấp nhận kết nối SSL. Trong pgnày được chỉ định bởi pg.defaults.ssl = true;. Làm thế nào để bạn làm điều này trong pg-promise?
ocram

@ocram github.com/vitaly-t/pg-promise/wiki/… hoặc bạn có thể chỉ định SSL trong các tham số kết nối: github.com/vitaly-t/pg-promise/wiki/Connection-Syntax
importanty-t

Tôi mới làm quen với hầu hết điều này: javascript, hứa hẹn, postgres, v.v. và đây chính xác là những gì tôi cần. Cảm ơn bạn!!
Ryan Rodemoyer

1
@ocram Tôi vừa nhận được điều này bằng cách thực hiệnpgp.pg.defaults.ssl = true;
CharlieC

điều này có tạo ra nhiều kết nối để tự động cải thiện thông lượng postgres khi chúng tôi đưa ra nhiều yêu cầu truy vấn cho postgres không?
sundar

5

Hồ bơi là cách để đi ngay bây giờ.

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

nó có thể được sử dụng như db.query('<BEGIN,COMMIT,ROLLBACK,your query,anything')


1

Tốt hơn là tạo một nhóm pg trên toàn cầu và mỗi khi bạn cần thực hiện thao tác db, hãy sử dụng ứng dụng khách và sau đó giải phóng nó trở lại nhóm. Khi tất cả các hoạt động db được thực hiện, kết thúc nhóm bằng cách sử dụngpool.end()

Mã mẫu -

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

        });
}

});  

Để biết thêm chi tiết, bạn có thể tham khảo bài blog của tôi - Nguồn


0

Như bạn có thể thấy từ tài liệu, cả hai tùy chọn đều hợp lệ, vì vậy hãy chọn tùy chọn nào bạn thích. Là bạn, tôi sẽ đi với sự lựa chọn thứ hai.


Điều gì về kết nối lại khi kết nối bị gián đoạn? Điều đó có được thực hiện tự động không? Trang wiki về xử lý lỗi là ... trống github.com/brianc/node-postgres/wiki/Error-handling
alltom

Tôi đã hỏi nó một cách riêng biệt: stackoverflow.com/questions/15619456/…
alltom

-1

Tôi quan tâm đến một trình xử lý rất đơn giản cho việc này nên tôi đã tự làm mà không làm cho nó quá phức tạp. Tôi không ảo tưởng rằng nó siêu cơ bản nhưng nó có thể giúp một số người bắt đầu. Về cơ bản, nó kết nối, chạy các truy vấn và xử lý lỗi cho bạn.

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

Sau đó, bạn sẽ sử dụng bằng cách gọi nó theo cách này:

runQuery("SELECT * FROM table", function(result) {
  // Whatever you need to do with 'result'
}

Điều này thậm chí không giải phóng kết nối trở lại nhóm. Nó sẽ làm cạn kiệt hồ bơi thực sự nhanh chóng. Ví dụ cơ bản trên node-postgrestrang làm tốt hơn điều này.
importanty-t

-2

Đây là cách tôi làm điều đó, một loại "tất cả các phương pháp ở trên"

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
Vì vậy, bạn sẽ không có quản lý kết nối, không hỗ trợ giao dịch và không hỗ trợ tác vụ. Điểm mấu chốt là gì?
importanty-t

1
ngôn ngữ gì vậy? cà phê? Berk
caub
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.