You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

高并发请求下PG Promise出现too many client错误如何解决?

解决方案

你遇到的too many clients错误核心是连接使用方式错误导致连接被不必要的占用耗尽,不需要调整数据库最大连接数,按以下步骤修改即可解决:

问题根因

  • 事务内调用全局db对象的方法而非事务上下文对象:db.tx回调中传入的t是当前事务绑定的专属连接,你直接用db.none执行插入会每次都从连接池申请新连接,单事务插入上千条数据会直接占满所有连接。
  • 异步逻辑无并发控制:call函数中的循环没有加await管控,5次数据查询+事务逻辑会同时触发,进一步放大连接占用量。
  • 批量插入实现方式不合理:逐行生成单条INSERT语句执行,本身会造成不必要的资源浪费,也会放大连接占用问题。

具体修改方案

1. 修正事务内的API调用

事务内所有数据库操作都使用事务上下文t对象的方法,不要直接调用全局db对象的方法,确保整个事务全程只用1个连接。

2. 改用批量插入语法,一次请求完成所有插入

使用pg-promise内置的helpers.insert工具生成多行插入的单条SQL,只需要执行1次查询就能完成所有批量插入操作,性能比逐行执行高10倍以上,也完全不会占用多余连接。

3. 增加异步流程控制,限制并发数

给循环内的异步操作加await,或者用限流机制控制同时运行的事务数量,避免短时间内同时申请过多连接。

修改后代码示例

// 初始化插入列模板,只需执行一次
const cs = new pgp.helpers.ColumnSet(['id', 'isdeleted', 'parentid'], {table: 'test_data'});

async function call(){
   // 可根据业务需要调整并发数,此处为串行执行避免占用过多连接
   for (let index = 0; index < 5; index++) {
        const result = await getPendingData();
        await db.tx(async (t) => {
            // 组装所有待插入的数据
            const insertValues = result.map(() => ({
                id: uuidv1(),
                isdeleted: 0,
                parentid: `${uuidv1()}x-${uuidv1()}`
            }));
            // 生成批量插入SQL,执行一次完成所有插入
            const insertSql = pgp.helpers.insert(insertValues, cs);
            await t.none(insertSql);
        });
   }
}

const getPendingData = async () => {
     return db.task('getPendingData', async (t) => {
         return await t.any('select * from other_table');
     });
}

call();

如果业务场景必须逐行执行插入语句,仅需要把原代码中事务内的db.none改为t.none,也能解决连接耗尽问题,只是性能比批量插入低。

内容的提问来源于stack exchange,提问作者Ronaldo Cristover

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.24 20:06:09