0

0

如何正确处理 pg-promise 中的批量事务与 Promise 错误捕获

碧海醫心

碧海醫心

发布时间:2026-01-05 19:49:02

|

261人浏览过

|

来源于php中文网

原创

如何正确处理 pg-promise 中的批量事务与 Promise 错误捕获

本文详解 pg-promise 批量数据库操作中因 promise 传递不当导致的未捕获异常问题,指出 `t.batch()` 已废弃,并提供基于显式 `await` 和统一错误处理的现代事务写法。

在使用 pg-promise 构建事务性数据库操作时,一个常见陷阱是:将已执行(即已返回 Promise 实例)的查询函数直接传入 t.batch(),而非在事务上下文内按需构造 Promise。这会导致错误无法被事务层捕获,进而引发 Uncaught Exception——尤其在数据库连接失败、SQL 语法错误或约束冲突等场景下,Node.js 进程可能意外崩溃。

根本原因在于:

  • addToColumn(...) 若不接收事务对象 t,默认使用全局 db 实例执行,其返回的 Promise 脱离事务上下文
  • 当该 Promise 被提前调用(如 batchQuery([...]) 中直接传入 addToColumn(...) 调用结果),它会在 db.tx() 启动前就已开始执行,甚至可能在事务开启失败后仍尝试连接数据库;
  • 此时 .catch() 仅作用于 db.tx() 返回的 Promise,而内部“游离”的 Promise 抛出的错误无人监听,最终成为未捕获异常。

✅ 正确做法:所有数据库操作必须在事务回调函数内、通过事务对象 t 执行,并避免过早求值。推荐使用 async/await 显式控制流程,而非依赖已废弃的 t.batch():

Mutiny
Mutiny

无代码AI平台,帮助营销人员将漏斗需求转化为收入。

下载
// ✅ 推荐:参数化 + 可选事务上下文
const addToColumn = (tableName, columnName, entryId, amountToAdd, t = db) => {
  return t.one(
    'UPDATE ${table:name} SET ${column:name} = ${column:name} + ${amount:csv} WHERE id = ${id:csv} RETURNING *',
    {
      table: tableName,
      column: columnName,
      amount: amountToAdd,
      id: entryId,
    }
  );
};

// ✅ 推荐:事务内显式 await,自动回滚 + 统一错误传播
const transferEnvelopeBudgetByIds = async (req, res, next) => {
  try {
    const result = await db.tx(async t => {
      const from = await addToColumn(
        'envelopes',
        'budget',
        req.envelopeFromId,
        -req.transferBudget,
        t
      );
      const to = await addToColumn(
        'envelopes',
        'budget',
        req.envelopeToId,
        req.transferBudget,
        t
      );
      return { from, to }; // 可选:返回结构化结果
    });

    req.updatedEnvelopes = result;
    next();
  } catch (err) {
    // 所有错误(连接失败、SQL 错误、约束冲突)均由此处统一捕获
    // pg-promise 自动回滚事务,无需手动处理
    next(err);
  }
};

⚠️ 注意事项:

  • 不要使用 t.batch():官方文档明确标注其为 obsolete,且语义模糊(易误解为“并发执行”,实则顺序 resolve);现代写法应使用 await 链式调用,语义清晰、调试友好、错误可追溯。
  • 禁止提前执行查询:切勿在 db.tx() 外调用 addToColumn(...) 并将返回的 Promise 塞入数组——这等于绕过事务控制。
  • 错误处理集中化:事务内的 try/catch 或顶层 catch() 已足够;每个查询函数内部 .catch()(如原代码中的 handleQueryErr)反而会吞掉关键错误,破坏事务原子性。
  • 事务对象 t 是必需的:确保所有参与事务的查询都显式传入 t,否则它们运行在独立连接上,既不共享事务隔离级别,也无法联动回滚。

总结:pg-promise 的事务可靠性取决于 Promise 的构造时机执行上下文。坚持“事务内构造、事务内执行、顶层捕获”的三原则,即可彻底规避未捕获异常,并获得强一致的 ACID 保障。

相关专题

更多
数据分析工具有哪些
数据分析工具有哪些

数据分析工具有Excel、SQL、Python、R、Tableau、Power BI、SAS、SPSS和MATLAB等。详细介绍:1、Excel,具有强大的计算和数据处理功能;2、SQL,可以进行数据查询、过滤、排序、聚合等操作;3、Python,拥有丰富的数据分析库;4、R,拥有丰富的统计分析库和图形库;5、Tableau,提供了直观易用的用户界面等等。

676

2023.10.12

SQL中distinct的用法
SQL中distinct的用法

SQL中distinct的语法是“SELECT DISTINCT column1, column2,...,FROM table_name;”。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

320

2023.10.27

SQL中months_between使用方法
SQL中months_between使用方法

在SQL中,MONTHS_BETWEEN 是一个常见的函数,用于计算两个日期之间的月份差。想了解更多SQL的相关内容,可以阅读本专题下面的文章。

346

2024.02.23

SQL出现5120错误解决方法
SQL出现5120错误解决方法

SQL Server错误5120是由于没有足够的权限来访问或操作指定的数据库或文件引起的。想了解更多sql错误的相关内容,可以阅读本专题下面的文章。

1091

2024.03.06

sql procedure语法错误解决方法
sql procedure语法错误解决方法

sql procedure语法错误解决办法:1、仔细检查错误消息;2、检查语法规则;3、检查括号和引号;4、检查变量和参数;5、检查关键字和函数;6、逐步调试;7、参考文档和示例。想了解更多语法错误的相关内容,可以阅读本专题下面的文章。

356

2024.03.06

oracle数据库运行sql方法
oracle数据库运行sql方法

运行sql步骤包括:打开sql plus工具并连接到数据库。在提示符下输入sql语句。按enter键运行该语句。查看结果,错误消息或退出sql plus。想了解更多oracle数据库的相关内容,可以阅读本专题下面的文章。

674

2024.04.07

sql中where的含义
sql中where的含义

sql中where子句用于从表中过滤数据,它基于指定条件选择特定的行。想了解更多where的相关内容,可以阅读本专题下面的文章。

571

2024.04.29

sql中删除表的语句是什么
sql中删除表的语句是什么

sql中用于删除表的语句是drop table。语法为drop table table_name;该语句将永久删除指定表的表和数据。想了解更多sql的相关内容,可以阅读本专题下面的文章。

412

2024.04.29

漫蛙2入口地址合集
漫蛙2入口地址合集

本专题整合了漫蛙2入口汇总,阅读专题下面的文章了解更多详细内容。

161

2026.01.06

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
WEB前端教程【HTML5+CSS3+JS】
WEB前端教程【HTML5+CSS3+JS】

共101课时 | 8.1万人学习

JS进阶与BootStrap学习
JS进阶与BootStrap学习

共39课时 | 3.1万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号