在nodejs中重用postgresql连接池

yes*_*day 5 postgresql node.js async-await

我在nodejs中有以下postgresql连接文件:

// postgresql.js

"use strict";

const { Pool } = require('pg');

module.exports = new Promise((resolve, reject) => {
  const pool = new Pool({
    host: '127.0.0.1',
    port: 5432,
    user: 'postgres',
    password: 'postgres',
    database: 'postgres',
    connectionTimeoutMillis: 0,
    idleTimeoutMillis: 0,
    min: 10,
    max: 20,
  });

  resolve({ pool });
});
Run Code Online (Sandbox Code Playgroud)

我使用 Promise 是因为稍后我将开始使用Google Cloud Secret Manager。秘密是异步获取的,因此服务器启动时无法建立数据库连接。

在我的控制器文件中,我像这样使用它:

// apicontroller.js

"use strict";

const postgresql = require('./postgresql');

app.get('/api/test', async (req, res, next) => {
// resolve the postgresql promise
const { pool } = await postgresql;

// resolve the pool.connect() promise
const client = await pool.connect();

// use the client object here
// eg. await client.query(...)
});
Run Code Online (Sandbox Code Playgroud)

问题不是它不起作用,相反,它就像一个魅力!但我在问自己:我是在重用连接池,还是在每次请求此路由时创建一个新的连接(池)?

这是仅重用一次数据库连接的正确方法吗?

编辑:我只包含相关的代码部分。

hur*_*ane 5

As it is explained in the documentation of node-postgres, I would use pool.query rather than using (handling) the client.

Single query, If you don't need a transaction or you just need to run a single query, the pool has a convenience method to run a query on any available client in the pool. This is the preferred way to query with node-postgres if you can as it removes the risk of leaking a client.

So my code would be like;

postgresql.js

let mainPool = null;

function createPool(){
  const pool = new Pool({
    host: '127.0.0.1',
    port: 5432,
    user: 'postgres',
    password: 'postgres',
    database: 'postgres',
    connectionTimeoutMillis: 0,
    idleTimeoutMillis: 0,
    min: 10,
    max: 20,
  });
  return pool;
}

function getPool(){
  if(!mainPool){
    mainPool = createPool();
  }
  return mailPool;
}

export default { getPool };
Run Code Online (Sandbox Code Playgroud)

controller.js

const { getPool } = require('./postgresql');

app.get('/api/test', async (req, res, next) => {
  getPool().query('SELECT * FROM users', [], (err, res) => {
    if (err) {
       return res.status(500).send(err);
    }
    return res.status(500).send(res);
  });
});
Run Code Online (Sandbox Code Playgroud)


Ber*_*rgi 0

是的,您正在重用作为导出的 Promise 结果存储的同一池对象。只有一个,没有代码可以创建第二个实例,无论您多久一次,该模块都只会评估一次require

然而,错误处理存在一个小问题 - 如果无法创建数据库池(例如,无法加载机密),您需要在某处处理此问题(并且可能导致应用程序崩溃),而不是等待事件unhandledrejection

虽然您的代码很好,但请考虑另一种方法,即在获取池(及其连接详细信息)之前不启动http服务器,然后将池(不是它的承诺)传递给所有路由。这还可以确保如果 http 服务器的依赖项无法初始化,则根本不会启动 http 服务器。