Next.js使用pg-promise设置ColumnSet时出现重复连接警告
问题根因
这个警告和ColumnSet配置无关,是Next.js开发模式热重载+单例逻辑写法缺陷导致的:
- 代码混用ES Module import和CommonJS require导入pg-promise,Next.js编译时模块缓存易失效,导致初始化逻辑重复执行
- pg-promise实例初始化写在模块顶层,每次模块被热重载重新执行时,还没走到单例判断逻辑就已经创建了新的初始化实例,重复生成同连接的数据库对象触发警告
修复方案
1. 重写数据库单例文件
把pgp实例、数据库连接的初始化逻辑全部放到单例判断内部,统一导入方式,用全局变量直接存储单例,适配Next.js热重载机制,修正后代码如下:
import ConfigEnv from 'utils/configuration'; import pgPromise, { IDatabase, IMain } from 'pg-promise'; const initOptions = { capSQL: true, }; interface IDatabaseScope { db: IDatabase<any>; pgp: IMain; } declare global { var __pgpSingleton: IDatabaseScope | undefined; } export function getDB(): IDatabaseScope { if (!global.__pgpSingleton) { const pgp = pgPromise(initOptions); const db = pgp(ConfigEnv.pgp); global.__pgpSingleton = { db, pgp }; } return global.__pgpSingleton; }
2. 调整API路由代码
原有API逻辑不需要大改,只需要移除冗余的Promise链式写法(已经用async/await不需要再嵌套.then),补个请求方法判断即可。ColumnSet本身是纯内存SQL生成对象,不会触发数据库连接,只需要初始化一次复用就行:
import { getDB } from 'db/pgpdb'; const { db, pgp } = getDB(); const cs = new pgp.helpers.ColumnSet([ '?detail_id', 'age', 'name' ], { table: 'user_detail', }); export default async (req, res) => { if (req.method !== 'POST') return res.status(405).end(); try { const update = pgp.helpers.update(req.body.content, cs) + ` WHERE v.detail_id = t.detail_id`; await db.none(update); return res.status(200).end(); } catch (error) { console.log('update error:', error); return res.status(500).send(error); } };
验证说明
- 修改完成后重启Next.js开发服务,清空之前的模块缓存,再调用接口就不会出现重复创建数据库对象的警告
- 生产环境下Next.js不会触发热重载,单例只会初始化一次,连接池复用正常,不存在连接泄漏问题
- ColumnSet配置本身和这个警告无关,不需要调整ColumnSet的字段定义逻辑
内容的提问来源于stack exchange,提问作者Jack
相关产品推荐
相关产品推荐

