我应该在哪里初始化 pg-promise

IT技术 javascript pg-promise
2021-01-31 16:44:18

我刚刚开始学习nodejs-postgres并找到了pg-promise包。我阅读了文档和示例,但我不明白应该将初始化代码放在哪里?我使用 Express 并且我有很多路线。

我必须将整个初始化(包括pg-monitorinit)放在我想查询数据库的每个文件中,或者我只需要initalize/configure在 server.js 中包含它们?

如果我只在 server.js 中初始化它们,我应该在需要 db 查询的其他文件中包含什么?

换句话说。我不清楚 pg-promise 和 pg-monitorconfiguration/initalization是全局操作还是本地操作?

还不清楚是否需要为每个查询创建一个 db 变量并结束 pgp?

var db = pgp(connection);

db.query(...).then(...).catch(...).finally(**pgp.end**);
2个回答

您只需要初始化数据库连接一次。如果要在module之间共享,则将其放入自己的module文件中,如下所示:

const initOptions = {
    // initialization options;
};

const pgp = require('pg-promise')(initOptions);

const cn = 'postgres://username:password@host:port/database';
const db = pgp(cn);

module.exports = {
    pgp, db
};

请参阅支持的初始化选项

更新-1

如果您尝试创建多个具有相同连接详细信息的数据库对象,库将向控制台输出警告:

WARNING: Creating a duplicate database object for the same connection.
    at Object.<anonymous> (D:\NodeJS\tests\test2.js:14:6)

这表明您的数据库使用模式不好,即您应该共享数据库对象,如上所示,而不是重新创建它。从 6.x 版本开始,它变得至关重要,每个数据库对象都维护自己的连接池,因此复制这些对象还会导致连接使用率下降。


此外,没有必要导出pgp- 初始化库实例。相反,你可以这样做:

module.exports = db;

如果在某些module中您需要使用库的根目录,您可以通过属性$config访问它

const db = require('../db'); // your db module
const pgp = db.$config.pgp; // the library's root after initialization

更新-2

一些开发人员已经报告(问题 #175)某些框架,例如 NextJS 设法以打破单例模式的方式加载module,这导致数据库module加载多次,并产生duplicate database警告,即使来自 NodeJS的观点它应该只是工作。

下面是解决此类集成问题的方法,通过使用Symbol强制单例进入全局范围让我们创建一个可重用的助手来创建单例......

// generic singleton creator:
export function createSingleton<T>(name: string, create: () => T): T {
    const s = Symbol.for(name);
    let scope = (global as any)[s];
    if (!scope) {
        scope = {...create()};
        (global as any)[s] = scope;
    }
    return scope;
}

使用上面的帮助程序,您可以将 TypeScript 数据库文件修改为:

import * as pgLib from 'pg-promise';

const pgp = pgLib(/* initialization options */);

interface IDatabaseScope {
    db: pgLib.IDatabase<any>;
    pgp: pgLib.IMain;
}

export function getDB(): IDatabaseScope {
    return createSingleton<IDatabaseScope>('my-app-db-space', () => {
        return {
            db: pgp('my-connect-string'),
            pgp
        };
    });
}

然后,在使用数据库的任何文件的开头,您可以执行以下操作:

import {getDB} from './db';

const {db, pgp} = getDB();

这将确保持久的单例模式。

@PirateApp 在侦听器连接中添加额外的细节,或者dc为主连接指定,因此它们被认为是不同的。
2021-03-19 16:44:18
@ggabor 绝对不是!请参阅库取消初始化
2021-03-22 16:44:18
谢谢,现在清楚了。pgp.end 呢?我应该把它放在每个查询的末尾吗?
2021-03-29 16:44:18
@vitaly-t 我只是按照上述方法进行操作。有一个帮助目录,我可以在其中创建连接并导出它并跨module使用它。第一次之后,每个module无论在何处使用该导出对象,都会抛出此警告。
2021-03-31 16:44:18
赞成!但是除了 pg-promise-demo 结构github.com/vitaly-t/pg-promise-demo之外,你如何添加一个强大的监听,根据演示我在 index.js 文件的 db 文件夹中找到了我的 db 和 pgp ,但我的一个表做了一个通知,我需要继续收听,当我有一个健壮的侦听器时,除了 db/index.js 结构之外,还有一个永久连接
2021-04-06 16:44:18

pgp 中的“连接”实际上是一个自动管理的多个连接池。每次发出请求时,都会从池中抓取一个连接,打开、使用,然后关闭并返回到池中。这就是为什么 Vitaly-t 为您的整个应用程序只创建一个 pgp 实例的重要原因。终止连接的唯一原因是,如果您确实已经使用完数据库,即您正在优雅地关闭应用程序。

这不是警告出现的原因。原因是因为 1) 是一种设计反模式,使用相同的连接重新初始化数据库 2) 每个数据库对象分别接收和处理其扩展性。参见 event extend,这会使协议不一致。
2021-04-09 16:44:18