使用 node.js postgresql module的正确方法是什么?

IT技术 javascript postgresql node.js heroku
2021-02-19 22:35:55

我正在 Heroku 上编写一个 node.js 应用程序并使用pg module我无法找出为我需要查询数据库的每个请求获取客户端对象的“正确”方法。

该文档使用如下代码:

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 的免费数据库实例无论如何都仅限于一个连接,但是这样做有什么缺点吗?每次使用之前,我是否需要检查我的客户端对象是否仍然连接?

6个回答

我是node-postgres的作者首先,我很抱歉文档未能明确说明正确的选项:这是我的错。我会努力改进它。刚刚了一篇 Gist来解释这一点,因为Twitter的谈话时间太长了。

使用pg.connect在 Web 环境中使用的方法

PostgreSQL 服务器每个连接一次只能处理 1 个查询。这意味着,如果您有 1 个全局new pg.Client()连接到您的后端,那么您的整个应用程序就会因 postgres 对查询的响应速度而陷入瓶颈。从字面上看,它会将所有内容排列起来,对每个查询进行排队。是的,它是异步的,所以没关系……但是您不想将吞吐量乘以 10 倍吗?使用pg.connect 设置 pg.defaults.poolSize为一些理智(我们做 25-100,还不确定正确的数字)。

new pg.Client是为了当你知道自己在做什么时。当您出于某种原因需要一个长期存在的客户端或需要非常小心地控制生命周期时。一个很好的例子是使用 LISTEN/NOTIFY. 监听客户端需要在周围和连接而不是共享,以便它可以正确处理NOTIFY消息。其他示例是打开 1-off 客户端以杀死一些挂起的东西或在命令行脚本中。

一件非常有用的事情是将应用程序中对数据库的所有访问集中到一个文件中。不要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

对不起,我对 DBMS 还很陌生,我在理解这一点上仍然有问题,但为什么我们不想“乱扔 pg.connect”调用呢?是为了简单还是出于性能原因?例如,我在基本应用程序中的每个路由中调用 pg.connect 一次(所有路由都具有相同的 conString)。这个可以吗?直觉上,每当我调用它(我不想要)时,它都感觉它正在与同一个数据库建立一个新连接,但它是否在内部使用池连接?谢谢。
2021-04-26 22:35:55
惊人的。为什么每个查询使用一个连接而不是每个请求一个连接?我一直在寻找一种合适的方法来在请求中的多个查询之间共享连接,并且在在这里找到答案之前一直在考虑 res.locals。
2021-04-26 22:35:55
如何关闭 pg 连接?
2021-05-07 22:35:55
请注意 pg.connect 在 node-postgres aka pg 的 v7 之后被删除。请参阅stackoverflow.com/questions/45174120/pg-connect-not-a-function
2021-05-08 22:35:55
等一下。您的解决方案似乎不支持事务。
2021-05-13 22:35:55

我是pg-promise的作者,它通过Promise简化了node-postgres 的使用。

它使用由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教程或项目主页 中找到更多示例

2021-04-15 22:35:55
当我们向 postgres 发出多个查询请求时,这会创建多个连接以自动提高 postgres 吞吐量吗?
2021-04-21 22:35:55
我对大部分内容都不熟悉:javascript、promises、postgres 等,这正是我所需要的。谢谢!!
2021-05-01 22:35:55
您好,Heroku 只接受 SSL 连接。pg这由 指定pg.defaults.ssl = true;你如何做到这一点pg-promise
2021-05-04 22:35:55
@ocram 我刚刚通过做这个工作 pgp.pg.defaults.ssl = true;
2021-05-11 22:35:55

游泳池是现在要走的路。像这样的事情

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

最好全局创建一个 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();

        });
}

});  

更详细的可以参考我的博文 -源码

正如您从文档中看到的,这两个选项都有效,因此请选择您喜欢的任何一个。和你一样,我会选择第二个。

当连接断开时重新连接怎么办?这是自动完成的吗?关于错误处理的 wiki 页面是...空github.com/briac/node-postgres/wiki/Error-handling
2021-04-21 22:35:55
我已经单独问过了:stackoverflow.com/questions/15619456/...
2021-05-09 22:35:55