【问题标题】:What is the proper way to use the node.js postgresql module?使用 node.js postgresql 模块的正确方法是什么?
【发布时间】:2012-01-19 01:01:08
【问题描述】:

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

文档使用如下代码:

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

但您肯定不需要在每个使用数据库的函数中调用pg.connect,对吧?我见过other code 这样做:

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

【问题讨论】:

    标签: javascript postgresql node.js heroku


    【解决方案1】:

    游泳池是现在要走的路。像这样的东西

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

    【讨论】:

      【解决方案2】:

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

      更多详情可以参考我的博文-Source

      【讨论】:

        【解决方案3】:

        我是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 教程或project's home page 中找到更多示例。

        【讨论】:

        • 嗨,Heroku 只接受 SSL 连接。在pg 中,这是由pg.defaults.ssl = true; 指定的。你是如何在pg-promise 中做到这一点的?
        • 我对其中的大部分内容都很陌生:javascript、promise、postgres 等,而这正是我所需要的。谢谢!!
        • @ocram 我刚刚通过pgp.pg.defaults.ssl = true;完成了这项工作
        • 当我们向 postgres 发出多个查询请求时,这会创建多个连接以自动提高 postgres 的吞吐量吗?
        【解决方案4】:

        我对一个非常简单的处理程序很感兴趣,所以我自己做了一个,但没有让它变得过于复杂。我并不幻想它是超级基本的,但它可以帮助一些人入门。基本上,它会为您连接、运行查询并处理错误。

        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 页面上的基本示例比这更好。
        【解决方案5】:

        这就是我的做法,有点像“上述所有方法”

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

        【讨论】:

        • 所以你最终将没有连接管理,没有事务支持,也没有任务支持。那有什么意义呢?
        • 那是什么语言?咖啡?伯克
        【解决方案6】:

        我是node-postgres 的作者。首先,我很抱歉文档未能明确说明正确的选择:这是我的错。我会努力改进它。我刚才写了a Gist 来解释这一点,因为the conversation 对于Twitter 来说太长了。

        在网络环境中使用pg.connect可行的方法

        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)。这个可以吗?直观地说,每当我调用它时,感觉就像是在与同一个数据库建立新连接(我不想要),但它是否在内部使用池连接?谢谢。
        • 太棒了。为什么每个查询使用一个连接而不是每个请求一个连接?我一直在寻找一种适当的方式来在请求中的多个查询之间共享连接,并且在在这里找到您的答案之前一直在考虑 res.locals。
        • 哦等等。您的解决方案似乎不支持事务。
        • 如何关闭pg连接?
        • 请注意,pg.connect 在 node-postgres aka pg 的 v7 之后被删除。见stackoverflow.com/questions/45174120/pg-connect-not-a-function
        【解决方案7】:

        documentation 中可以看出,这两个选项都有效,因此请选择您喜欢的选项。和你一样,我会选择第二个选择。

        【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-03-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-03-10
        • 1970-01-01
        • 2012-05-14
        相关资源
        最近更新 更多