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

Phi*_*lip 93 javascript postgresql heroku node.js

我正在Heroku上编写一个node.js应用程序并使用pg模块.我无法弄清楚为查询数据库所需的每个请求获取客户端对象的"正确"方法.

该文档使用如下代码:

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

但是你肯定不需要调用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
Run Code Online (Sandbox Code Playgroud)

我倾向于第二个选项,因为我相信Heroku的免费数据库实例无论如何仅限于一个连接,但是这样做有什么缺点吗?在使用之前,我是否需要检查我的客户端对象是否仍然连接?

小智 153

我是node-postgres的作者.首先,我道歉文档未能使正确的选项明确:这是我的错.我会尝试改进它.我刚才写了一篇Gist来解释这一点,因为Twitter 的谈话时间太长了.

使用pg.connect进入 Web环境的方法.

PostgreSQL服务器每个连接一次只能处理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);
        })
      });
   }
}
Run Code Online (Sandbox Code Playgroud)

通过这种方式,您可以将实现从pg.connect更改为自定义客户端池或其他任何内容,并且只需在一个位置更改内容.

看一下执行此操作的node-pg-query模块.

  • 对不起,我是DBMS的新手,我仍然有一个问题,但为什么我们不想"垃圾pg.connect"电话?是为了简单还是由于性能原因?例如,我在我的基本应用程序中的每个路径中调用pg.connect一次(所有路径都具有相同的conString).这个可以吗?直觉上,每当我调用它(我不想要)时,感觉就像它正在建立一个到同一个db的新连接,但它是否在内部使用池化连接?谢谢. (2认同)
  • 等一下.看起来您的解决方案不支持交易. (2认同)

vit*_*y-t 22

我是pg-promise的作者,它通过promises 简化了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);
    });
Run Code Online (Sandbox Code Playgroud)

即,您在执行查询时不需要处理连接逻辑,因为您只在全局设置连接一次,如下所示:

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;
Run Code Online (Sandbox Code Playgroud)

您可以在Learn by Example教程或项目主页上找到更多示例.


ama*_*mar 9

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

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)
      }
Run Code Online (Sandbox Code Playgroud)

它可以用作 db.query('<BEGIN,COMMIT,ROLLBACK,your query,anything')