Node.js postgresql modülünü kullanmanın doğru yolu nedir?


95

Heroku'da bir node.js uygulaması yazıyorum ve pg modülünü kullanıyorum . Veritabanını sorgulamam gereken her istek için bir istemci nesnesi almanın "doğru" yolunu bulamıyorum.

Dokümantasyon şu şekilde kod kullanır:

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

Ama kesinlikle pg.connectveritabanını kullanan her işlevi aramanıza gerek yoktur, değil mi? Bunu yapan başka bir kod gördüm :

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 için ücretsiz veritabanı örneğinin yine de tek bir bağlantıyla sınırlı olduğuna inandığım için ikinci seçeneğe yöneliyorum, ancak bunu bu şekilde yapmanın herhangi bir sakıncası var mı? Her kullanmadan önce istemci nesnemin hala bağlı olup olmadığını kontrol etmem gerekir mi?

Yanıtlar:


158

Ben yazar değilim düğüm-Postgres'e . İlk olarak, dokümantasyon doğru seçeneği netleştiremediği için özür dilerim: bu benim hatam. Onu geliştirmeye çalışacağım. Biraz önce bunu açıklamak için bir Özet yazdım çünkü konuşma Twitter için çok uzadı.

Kullanımı pg.connectise gitmek için bir yol , bir web ortamında.

PostgreSQL sunucusu, bağlantı başına bir seferde yalnızca 1 sorguyu işleyebilir. Bu new pg.Client(), arka ucunuza 1 global bağlıysanız, postgres'in sorgulara ne kadar hızlı yanıt verebildiğine bağlı olarak uygulamanızın tamamının tıkanacağı anlamına gelir . Kelimenin tam anlamıyla, her sorguyu sıraya koyarak her şeyi sıralayacaktır. Evet, eşzamansız ve sorun değil ... ama veriminizi 10x ile çarpmayı tercih etmez miydiniz? Kullanın aklı başında bir şeye pg.connect ayarlayın pg.defaults.poolSize(25-100 yapıyoruz, henüz doğru sayıdan emin değiliz).

new pg.Clientne yaptığınızı bildiğiniz zamanlar içindir. Herhangi bir nedenle tek bir uzun ömürlü müşteriye ihtiyacınız olduğunda veya yaşam döngüsünü çok dikkatli bir şekilde kontrol etmeniz gerektiğinde. Bunun güzel bir örneği, kullanım zamanıdır LISTEN/NOTIFY. Dinleyen istemcinin, NOTIFYmesajları düzgün bir şekilde işleyebilmesi için etrafta olması ve bağlantılı olması ve paylaşılmaması gerekir . Diğer bir örnek, bazı asılı şeyleri öldürmek için 1 defalık bir istemciyi açarken veya komut satırı komut dosyalarında olabilir.

Çok yararlı bir şey, uygulamanızdaki veritabanınıza tüm erişimi tek bir dosyada merkezileştirmektir. pg.connectAramaları veya yeni müşterileri çöp kutusuna atmayın . Şuna benzer bir dosya olsun 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);
        })
      });
   }
}

Bu şekilde, uygulamanızı pg.connectözel bir müşteri havuzundan veya herhangi bir şekilde değiştirebilir ve yalnızca bir yerde değişiklik yapmanız gerekir.

Bunu yapan düğüm-pg-sorgu modülüne bir göz atın .


2
Üzgünüm, DBMS konusunda oldukça yeniyim ve hala bunu anlamakta sorun yaşıyorum, ama neden "litter pg.connect" çağrılarını istemiyoruz? Basitlik için mi yoksa performans nedeniyle mi? Örneğin, temel uygulamamda sahip olduğum her rotada pg.connect'i bir kez çağırıyorum (hepsi aynı bağlantıyla). Bu olur mu? Sezgisel olarak, her aradığımda aynı db ile yeni bir bağlantı kuruyormuş gibi geliyor (ki istemiyorum), ancak havuzlanmış bağlantıları dahili olarak kullanıyor mu? Teşekkürler.
user1164937

Harika. Neden istek başına bir bağlantı yerine sorgu başına bir bağlantı kullanıyorsunuz? Bir istek içindeki birden fazla sorgu arasında bir bağlantıyı paylaşmanın uygun bir yolunu arıyordum ve cevabınızı burada bulmadan önce res.locals'i düşünüyordum.
Joe Lapp

2
Bekle. Görünüşe göre buradaki çözümünüz işlemleri desteklemiyor.
Joe Lapp

1
PG bağlantısı nasıl kapatılır?
Vardan

1
Pg.connect'in, node-postgres aka pg. Bkz stackoverflow.com/questions/45174120/pg-connect-not-a-function
Colin D

24

Ben yazarı değilim pg-sözünün kullanılmasını kolaylaştıran, düğüm-Postgres'e vaat yoluyla.

Otomatik işlemler gibi diğer şeylerin yanı sıra node-postgres tarafından uygulanan bağlantı havuzunu kullanarak veritabanına bağlanmanın ve bağlantıyı kesmenin doğru yolu ile ilgili sorunları ele alır .

Pg- promise'daki bireysel bir istek , iş mantığınızla tam olarak alakalı olana indirgenir:

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

yani, sorguları yürütürken bağlantı mantığıyla uğraşmanıza gerek yoktur, çünkü bağlantıyı yalnızca bir kez, genel olarak şu şekilde kurarsınız:

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;

Örneklerle Öğren eğitiminde veya projenin ana sayfasında daha birçok örnek bulabilirsiniz .


Merhaba, Heroku yalnızca SSL bağlantılarını kabul eder. Gelen pgbu belirtilir pg.defaults.ssl = true;. Bunu nasıl yaparsınız pg-promise?
23'16

@ocram github.com/vitaly-t/pg-promise/wiki/… veya bağlantı parametreleri içinde SSL belirtebilirsiniz: github.com/vitaly-t/pg-promise/wiki/Connection-Syntax
vitaly-t

Bunların çoğunda yeniyim: javascript, vaatler, postgres, vs. ve tam da ihtiyacım olan şey bu. Teşekkür ederim!!
Ryan Rodemoyer

1
@ocram Bunu yaparak çalıştımpgp.pg.defaults.ssl = true;
CharlieC

bu, postgres'e birden fazla sorgu isteği verdiğimizde postgres verimini otomatik olarak iyileştirmek için birden fazla bağlantı oluşturacak mı?
sundar

5

Havuz şimdi gitmenin yolu. Bunun gibi bir şey

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

olarak kullanılabilir db.query('<BEGIN,COMMIT,ROLLBACK,your query,anything')


1

Global olarak bir pg havuzu oluşturmak daha iyidir ve bir db işlemi yapmanız gerektiğinde, istemciyi kullanın ve ardından havuza geri bırakın. Tüm db işlemleri tamamlandıktan sonra havuzu kullanarak sonlandırınpool.end()

Basit kod -

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

        });
}

});  

Daha fazla ayrıntı için blog yazıma bakabilirsiniz - Kaynak



-1

Bunun için çok basit bir işleyiciyle ilgileniyordum, bu yüzden aşırı karmaşık hale getirmeden kendim yaptım. Bunun süper basit olduğuna dair bir yanılsama yaşamıyorum ama bazı insanların başlamasına yardımcı olabilir. Temel olarak, sizin için bağlanır, sorgular çalıştırır ve hataları işler.

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

O zaman şu şekilde adlandırırsınız:

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

Bu, bağlantıyı tekrar havuza bırakmaz. Havuzu çok hızlı tüketecek. node-postgresSayfadaki temel örnek bundan daha iyisini yapar.
vitaly-t

-2

İşte bunu nasıl yapıyorum, bir çeşit "yukarıdakilerin tümü"

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
Böylece bağlantı yönetimi, işlem desteği ve görev desteği olmayacak. Öyleyse ne anlamı var?
vitaly-t

1
bu hangi dil? Kahve? berk
caub
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.