# @dbx-tools/postgres 中文文档

规范地址：https://npmcn.com/package/%40dbx-tools/postgres/

版本：0\.9\.206
npm 元数据更新时间：2026-11-10T19:18:50.346Z
中文译文更新时间：2026-11-11T17:22:16.964Z
软件包许可：Apache-2\.0

本文由上游 README 翻译，可能存在偏差，请结合原文核对 API、命令与配置。版权与许可归原作者所有。

原始 npm 页面：https://www.npmjs.com/package/%40dbx-tools/postgres
原文对照：https://npmcn.com/package/%40dbx-tools/postgres/?lang=original
项目主页：https://github.com/reggie-db/dbx-tools#readme
源码仓库：https://github.com/reggie-db/dbx-tools

## 关键信息（来自 npm 元数据）

- 包体积（解压后）：248 kB，25 个文件
- 模块格式：ES Module
- TypeScript 类型：包内自带
- 运行依赖：3 个
- peer 依赖：@databricks/appkit 0\.81\.0
- 首次发布：2026-08-03T04:42:17.497Z
- 最新版本发布：2026-11-10T19:18:50.016Z
- 近 30 天下载量：12098（2026-10-12 至 2026-11-10，npm 官方下载统计）
- 已发布版本数：251（近 12 个月 251 个）

## 中文简介

连接正确的 PostgreSQL 咨询锁和 optEN/NOTIFY 节点主题总线

## 安装

```sh
npm install @dbx-tools/postgres
```

也可以使用：`pnpm add @dbx-tools/postgres`、`yarn add @dbx-tools/postgres`、`bun add @dbx-tools/postgres`

## README

# @dbx-工具/邮递

使用连接正确的 PostgreSQL 咨询锁和结构化 `LISTEN`编号 :`NOTIFY` 主题总线来自Node.js. 软件包还提供了可选 消息持续性、发送者身份和连接帮助者.

都与平地为敌 `pg.Pool` 或任何结构上与一个, 包括 AppKit 的 Lakebase 插件导出, 因此一个 Databricks App 获得 它们没有第二个数据库客户端或连接池.

## 快开始

在持有锁的 PostgreSQL 连接上运行受保护的工作 :

```ts
import { postgresConnectionOptions, withAdvisoryLock } from "@dbx-tools/postgres";
import { Pool } from "pg";

const pool = new Pool(postgresConnectionOptions({}));
const invoiceId = 42;

await withAdvisoryLock(pool, ["invoice", invoiceId], async (client) => {
  await client.query("UPDATE invoices SET status = 'sent' WHERE id = $1", [invoiceId]);
});
```

## 能力

-   转换任意结构键(字符串、阵列、对象、, `Date`,或一个 明确 `bigint`)成为稳定签名的64位咨询锁标识符.
-   从任何识别频道中获取合法的 Postgres 频道名称,所以不 调用网站必须将应用程序名称或租户身份标识进行消毒.
-   对整个召回的专用集合连接有一个会话锁定, 并且把连接到回调器上 所以保护的活在它上.
-   持有解析释放的交易锁定 `COMMIT` 或者说 `ROLLBACK`,这是 一次性安装需要什么.
-   广播a `type`编号 :`metadata`编号 :`body` 每个监听过程的封装 `pg_notify`,按正在处理的专题过滤.
-   填充工程、机器、进程、部署和可选的 AppKit 发送器 上下文,调用元数据总是获胜.
-   拒绝不会在JSON往返中幸存的有效载荷 电话站而不是电线上.
-   重新连接一个已丢弃的收听器, 用户仍保留时, 设定了后退 .
-   可选地坚持每条已发布的消息到一个软件包的表格,所以 未收听的订阅者可以通过光标重放历史, 默认 TTL和清理在插入.
-   两种有效载荷样式:通知中的整个信封,或指向 听者读回. 指针抬起八千字节 `NOTIFY` 限制和保留 表格赠款背后的内容.

## 会议作用

设定 `DBX_TOOLS_POSTGRES_ROLE` 当每个仓库拥有的 PostgreSQL 连接时 认证后应承担一个角色. `postgresConnectionOptions()` 添加 作用 `pg` 和 AppKit Lakebase 池的启动选项,同时 `postgresServerSettings()` 返回等同点 `asyncpg` 服务器设置.

```ts
import { postgresConnectionOptions } from "@dbx-tools/postgres";
import { Pool } from "pg";

const pool = new Pool(postgresConnectionOptions({}));
```

明确的第二个参数压倒环境值。 帮助者保留 现有 `options`,包括语句超时,并附加角色设置. 使用 `postgresRoleStatement()` 仅用于设置工作,该工作必须在 连接已经打开 .

当这些选项配置 AppKit Lakebase 路由池时,它们适用于其 服务-主要和每个用户OBO集合。 每一个可以到达的登录身份 因此,人才库必须是所配置角色的成员,否则 权限 `SET ROLE`,在游泳池成功连接之前.

## 与 AppKit Lakebase 一同使用

使用 AppKit `lakebase()` 以获取和刷新 PostgreSQL 池。 这个包 不替换该插件。 当工作需要连接正确咨询时添加 锁或交叉连接 `LISTEN`编号 :`NOTIFY` 交付、能力 Lakebase 插件不提供 .

## 咨询锁

```ts
import { postgresConnectionOptions, withAdvisoryLock } from "@dbx-tools/postgres";
import { Pool } from "pg";

const pool = new Pool(postgresConnectionOptions({}));

await withAdvisoryLock(pool, ["invoice", invoiceId], async (client) => {
  await client.query("UPDATE invoices SET status = 'sent' WHERE id = $1", [invoiceId]);
});
```

运行保护工程 `client` 调用接收。 A 类 `pool.query()` 内召回可能降落 在不同的连接上, 这不是一个 拿着锁.

使用交易范围帮助一次性数据库工作 :

```ts
import { withAdvisoryTransactionLock } from "@dbx-tools/postgres";

await withAdvisoryTransactionLock(pool, { schema: "my_feature", version: 1 }, async (client) => {
  await client.query("CREATE TABLE IF NOT EXISTS my_feature.events (id bigint primary key)");
});
```

`identity.advisoryLockId(key)` 暴露与 JSON 安全小数相同的减少 绳子。 A 类 `bigint` 键为 直接使用( 缩到64比特) 而不是散列, 因此锁可以交互操作 和另一个发布其数字锁标识的应用程序,例如 `pgmq`是因为 例如安装器锁. 任何其它东西都用 `object.toStableKey` 从 `@dbx-tools/shared-core` {\\fn黑体\\fs22\\bord1\\shad0\\3ahbe\\4ah00\\fscx67\\fscy66\\2chffffff\\3ch808080}那么关键顺序 对象在 a 时无关紧要 `1` (单位:千美元) `"1"` 保持不同的锁。 一个阵列是 读作若干部分,所以 `["invoice", 7]` 财务报告和审定财务报表 `"invoice_7"` 是不同的锁。 A 类 非无限数字或循环键抛出 `TypeError` 而不是产生一个 两个打电话的人可能不同意.

## 主题总线

```ts
import { PostgresTopicBus } from "@dbx-tools/postgres";

const bus = new PostgresTopicBus(pool, {
  metadata: async () => ({ publicIp: await resolvePublicIp() }),
  onError: (cause) => logger.error("bus", { cause }),
});

const unsubscribe = await bus.listen("orders", ({ type, metadata, body }) => {
  console.log(type, metadata.project, body);
});

await bus.broadcast("orders", {
  type: "order.updated",
  metadata: { traceId: "abc-123" },
  body: { orderId: "123", status: "ready" },
});

await unsubscribe();
await bus.close();
```

在频道上监听的每个过程都会收到每个消息. 没有 竞争的消费者。 巴士适合每个浏览器的SSE流等现场播放 选项卡,缓存无效或存在 ping。 它不分配工作. 默认只提供现场直播。 打开 `persist` 当 a 订阅者需要重放,需要时使用真正的队列.

### 信件信封

| 外地 | 来源 | 页:1 |
| --- | --- | --- |
| `id` | 公共汽车 | 每个消息在实例中都独一无二。 用来去除或作为 `id:`。 。 。 . |
| `topic` | 公共汽车 | 这个 `broadcast` 主题。 其他话题的听众从不看. |
| `type` | 呼叫器 | 例如事件名称 `order.updated`。必须的,没有空白. |
| `metadata` | 合并 | 呼叫器下的自动上下文 。 见下文. |
| `body` | 呼叫器 | 顺利通过. |
| `publishedAt` | 公共汽车 | ISO-8601,取自出版商的时钟,不是数据库的. |

`publishedAt` 财务报告和审定财务报表 `id` 用于显示和调试。 也没有命令信件 不同的情况可靠.

### 元数据优先

最弱到最强:自动机器上下文,然后是AppKit发送器身份,然后是 公交车 `metadata` 选项,然后是每个消息 `metadata`键入 更坚固的地层从不被覆盖 所以通过 `project` 明确替换 推断出一个 明确 `null` 也保存并阻止自动值 从用于那个键.

自动键, 当解析为无时, 每个键都会省略 : `project` (从) `DATABRICKS_APP_NAME`, (中文(简体) ), `DATABRICKS_BUNDLE_NAME`, (中文(简体) ), `PROJECT_NAME`,或 `npm_package_name`, (中文(简体) ), `hostname`, (中文(简体) ), `platform`, (中文(简体) ), `environment`, (中文(简体) ), `appName`, (中文(简体) ), `deploymentId`,以及 `databricksHost`. 公共/客户IP、进程ID、CPU 架构、运行时名称和运行时版本被故意忽略: 皮条很吵(而且往往很敏感),其余的都是每次部署的常数,以及 每条信息都会按有效载荷限制支付 通过 a `metadata` 函数,当一个进程需要其中一个这些值时.

上面的例子将一个发现的公用IP附以这种方式. 函数运行于 每一个广播, 所以记住任何昂贵的.

与可选 `@databricks/appkit` 已安装端点和用户执行上下文 活动, `senderId`, (中文(简体) ), `senderName`,以及 `senderEmail` 还加上了。 AppKit 为 进口懒惰且不需要。 在请求之外,或者没有包裹 公交车跳过那些键.

### 支持的信息值

身体和元数据必须活下来 `JSON.parse(JSON.stringify(x))` 不变,哪些 更为严格 `JSON.stringify` 不扔东西。 A 类 `Date` 成为弦, `NaN` 财务报告和审定财务报表 `Infinity` 变成 `null`页:1 `Map` 变成 `{}`,以及 `undefined` 失踪了. 每一个都到达听众的身边, 与所发送的东西不同, 所以所有他们 掷出 `TypeError` 在电话中代替。 周期、功能、符号、比值和类 由于同样的原因,拒绝提交案件.

规矩在 `@dbx-tools/shared-core` 作为 `object.isSerializableValue` 财务报告和审定财务报表 `object.SerializableValue`,因此,一个路由可以对不可信 请求正文并回答400而不是500,浏览器侧调用器可以共享 类型.

编码后的信封被封为 7900 字节, 在 PostgreSQL 的 8000 字节下 `NOTIFY` 有限度的,有大势的 `RangeError`自动元数据计数 反之,所以广播一个参考 并让接收器获取任何重大的东西.

### 连接、生命周期和失败

出版每通电话借用集合连接. 听力无法 : `LISTEN` 实值 会话状态,所以总线会检查一个专用客户端,并保持它多久 因为它有订阅者,但许多专题和听众都登记在册。 大小 带着那长生不老的检查表去游泳.

第一次之前没有联系 `listen`,或明示 `start()` 你何时会 最好找出一个连接问题 在启动. `close()` 释放客户端 并且是必需的。 用主机的停机钩登记 封闭的公交车停放 关闭并投掷,而不是静默地重新连接.

当通知连接中断时,总线会自行重新连接:立即 首先,将上限从250米翻一番,无限期地翻一番 订户仍然存在。 Postgres 重启或旋转 Lakebase 证书回收 没有干预。 空隙期间发布的消息会丢失 。 每一个失败 尝试,每个中断的连接, 和每个播放者 丢弃 结束 `onError`,它默认吞下它们。 配置登录器 任何长期运行。 一个失败的听众从来不影响出版商或其他人 听众.

一个频道包含许多话题,所以增加一个话题并不花费什么. 给一个 不相关的高音量流 自己的频道,因为每次听 会话解码频道上的每个消息.

### 重放为 `persist`

`NOTIFY` 没有重放: 一个不听的过程永远不会知道它是什么 错过了。 设定 `persist` 并且每个已发布的消息都是相同的 交易作为其通知,因此光标可以读取历史.

```ts
const bus = new PostgresTopicBus(pool, { persist: true });

await bus.broadcast("orders", { type: "order.updated", body: { id: 7 } });

let cursor: string | undefined;
do {
  const page = await bus.history("orders", { after: cursor, limit: 100 });
  for (const { message, expiresAt } of page.messages) handle(message, expiresAt);
  cursor = page.nextCursor;
} while (cursor);
```

该行和通知共同承诺,这就是整个财产 设计的基础是: `NOTIFY` 是在承诺时而不是在发言时交付的,所以 永远不能告诉听众它还不能读的一行.

| 选项 | 默认 | 行为 |
| --- | --- | --- |
| `schema` | `dbx_message_bus` | Schema用于信件的持久性. |
| `scope` | `open` | 哪一级的表格发布,历史默认读取. |
| `tables` | `*_messages` | 覆盖管理下的安装的分级表格名称. |
| `ttl` | `24 hours` | 万事通过期. `false` 保留信件直到删除. |
| `payload` | `envelope` | `pointer` 仅以路由方式通知。 见下文. |
| `cleanupBatchSize` | `1000` | 已过期的行被删除, 每一份持续出版 . |
| `provision` | `true` | 创建首先使用的图、表和索引. |

消息 EXPIRE 默认。 24小时TTL是默认的,正因为 未绑定的消息表是此特性否则会引入的失败 . 已过期的行被删除,在每份持续出版的限定批次 `cleanupExpired()` 按要求进行同样的扫荡. `ttl: false` 选择一个总线(或 `{ ttl: false }` 单曲 `broadcast`)出为已出. 虽然有,但.. 这不是默认.

两层, `open` 财务报告和审定财务报表 `restricted`,所以一个信道可以携带信息 不同的读者群:它们是单独的表格,所以一个角色被赋予了开放性 表格不能读取限制性历史. `messageBusGrantStatements(roles, scope, options)` 发放的补助额为: `history` 光标已绑定 至其所出之阶. 在限定的表格中恢复开放页面 舍去掉别人的行 发布到分级 每个消息 `broadcast(topic, { scope: "restricted", ... })`。 。 。 .

设定 `provision: false` 当移民拥有这个计划时 声明是: 在咨询交易锁下,否则适用一次,因此同时适用 在启动时安装的例不比赛 .

### 信封或指针

`payload: "envelope"` (缺省)将整个消息放入通知. 一次往返,不读放大,以PostgreSQL的有效载荷限制为界.

`payload: "pointer"` 仅以路线和身份通知 (单位:千美元)`{ v, scope, topic, id, sequence }`),收听者读回信封. 这样就大了 完全限制(一个大于7900字节的身体只能以这种方式公布)和 意思是没有级表补助的订户得知出了事 没有学会什么。 费用为每份通知读取一次。 听众收到 同样的 `TopicMessage` 无论是哪种方式。 上面的区别是看不见的 `listen`。 。 。 .

已经走光的指针( TTL 清理赢得比赛) 或无法读取 提高不会产生任何效果, 使用 `decodePointer` 如果非公共汽车消费者需要阅读原始通知.

### 命名频道

`channel` 使用任何识别通道, 而不是一个预先保密的标识 : 姓名、房客身份证、 `[env, feature]` 组合,或配置对象。 一个或多个值: 一个阵列被读取为多个部分,其他任何部分被读取为一体.

```ts
new PostgresTopicBus(pool, { channel: "billing-events" }).channelName;
// "billing_events_3x55ck"
new PostgresTopicBus(pool, { channel: ["billing", "production"] }).channelName;
// "billing_production_008jgf"
```

部分被标记成可读的半个和短的散列 窗体( e)`object.toStableKey`页:1 大麻是制图的原因 信得过: 孤独的象征是迷失的,所以 `my-app`, (中文(简体) ), `my_app`,以及 `myApp` 将 崩溃到一个信道上,并且名称长度足以击中 Postgres 的 63 个字符 限制会与任何分享主要标志的东西相撞。 用后缀 可读部分保持可读性,不同投入保持差异,包括 `["billing", "prod"]` 对 `"billing_prod"`,结构不同.

衍生是决定 跨过程和运行, 所以每个参与者 同一航道上降落时没有协调 对象密钥 秩序无关紧要。 不同的拼写方式有 读取 `bus.channelName` 来看 一组部分是否同意或确认两个进程。 默认为 a 共享 `dbx_tools_topic_bus` 频道.

`identity.channelName(parts)` 不搭公交车就暴露出原因, 用于配置检查和交叉运行的合同测试.

## 连接寿命周期

咨询锁是连接范围,不正确的池使用可能隐蔽地失败: 带着锁 `pool.query()` 与他人一起从事受保护的工作 `pool.query()` 可以用两个不同的连接, 所以锁保护什么 代码看起来是正确的。 这同样适用于 `LISTEN`,即会话状态 a 集合查询无法维持 。 这些帮手将两个生命周期都保持专注 连接和仅依赖 `pg`。 。 。 .

AppKit供应了"湖基"游泳池. 这些帮助者添加了锁和交叉连接 在它上面发送消息.

## 模块映射

| 模块 | 目的 |
| --- | --- |
| `advisoryLock` | 稳定锁ID+会话-和交易范围锁帮助器. |
| `identity` | 跨运行时的咨询锁和频道身份政策. |
| `topicBus` | 专题公交和信息合同. |
| `persistence` | 存储信息计划 赠款 TTL清理 历史 指针线. |

两个模块也被平整到软件包根上,所以 `import { withAdvisoryLock, PostgresTopicBus } from "@dbx-tools/postgres"` 工作内容 没有命名空间.

## 常见问题

### @dbx-tools/postgres 是什么？

连接正确的 PostgreSQL 咨询锁和 optEN/NOTIFY 节点主题总线

### 如何安装 @dbx-tools/postgres？

在项目目录运行 npm install @dbx-tools/postgres，或使用 pnpm add / yarn add / bun add。

### @dbx-tools/postgres 支持 TypeScript 吗？

支持。包内自带 TypeScript 类型声明（package\.json 声明了 types 入口），安装后即可获得类型提示，无需再安装 @types 包。

### @dbx-tools/postgres 支持 ESM 还是 CommonJS？

以 ES Module 形式发布，推荐使用 import 引入。在 CommonJS 项目中，Node\.js 20\.19\+ / 22\.12\+ 可以直接 require\(\) 不含顶层 await 的 ES Module，更早的版本需要改用动态 import\(\)。

### @dbx-tools/postgres 可以商用吗？

@dbx-tools/postgres 使用 Apache-2\.0 许可。宽松许可：允许商业使用、修改和再分发，并附带明确的专利授权；分发时需保留许可与 NOTICE 文件，修改过的文件要注明改动。以上为概括，不构成法律意见，请以许可原文为准。

### @dbx-tools/postgres 的下载量有多少？

根据 npm 官方下载统计，@dbx-tools/postgres 在 2026/10/12 – 2026/11/10 这 30 天内被下载 12,098 次，日均约 403 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入，适合横向比较热度，不能直接等同于使用人数。

### @dbx-tools/postgres 还在维护吗？

最新版本 0\.9\.206 发布于 2026/11/11（今天）；至今共发布 251 个版本，其中过去 12 个月发布了 251 个；首次发布于 2026/08/03。发布频率只是参考信号：功能稳定的工具可能很少需要更新，建议结合源码仓库的 issue 和提交记录判断。

