# @aws-blocks/bb-distributed-table 中文文档

规范地址：https://npmcn.com/package/%40aws-blocks/bb-distributed-table/

版本：0\.3\.0
npm 元数据更新时间：2026-11-02T10:24:51.504Z
中文译文更新时间：2026-11-07T13:33:58.490Z
软件包许可：Apache-2\.0

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

原始 npm 页面：https://www.npmjs.com/package/%40aws-blocks/bb-distributed-table
原文对照：https://npmcn.com/package/%40aws-blocks/bb-distributed-table/?lang=original
项目主页：https://github.com/aws-devtools-labs/aws-blocks/tree/main/packages/bb-distributed-table#readme
源码仓库：https://github.com/aws-devtools-labs/aws-blocks

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

- 包体积（解压后）：564 kB，53 个文件
- 模块格式：ES Module
- TypeScript 类型：包内自带
- 运行依赖：7 个
- peer 依赖：constructs ^10\.6\.0，aws-cdk-lib ^2\.257\.0
- 首次发布：2026-06-15T23:39:19.641Z
- 最新版本发布：2026-11-02T10:24:51.115Z
- 近 30 天下载量：63453（2026-10-07 至 2026-11-05，npm 官方下载统计）
- 已发布版本数：15（近 12 个月 15 个）

## 中文简介

结构化数据存储由DynamoDB支持,具有二级索引和丰富的查询能力.

## 安装

```sh
npm install @aws-blocks/bb-distributed-table
```

也可以使用：`pnpm add @aws-blocks/bb-distributed-table`、`yarn add @aws-blocks/bb-distributed-table`、`bun add @aws-blocks/bb-distributed-table`

## README

# 已分发 图表

结构化数据存储由DynamoDB支持,具有二级索引和丰富的查询能力.

**何时使用 :** 您需要通过多个字段查询,使用复合键,或者执行以排序为基础的范围查询. 对有关系,时间序列数据和需要多个索引的存取模式的实体有好处.

**不使用时 :** 如果您只需要单键检查, 请使用 `KVStore`。如果需要完整的 SQL(joins,聚合),则使用 `Database`。 。 。 .

> 设计与模拟等价细节 : [设计](https://npmcn.com/package/%40aws-blocks/bb-distributed-table/DESIGN.md)

## API 密码

```typescript
const table = new DistributedTable(scope, id, options)
```

> **类型推论( 重要 ):** 执行 **没有** 通过一个单一的显式类型参数,例如 `new DistributedTable<MyType>(...)`。只做这样的针 `T` 并让密钥/索引的通用符号回到其广泛的默认值,这打破了密钥类型的推论—— `get()` 财务报告和审定财务报表 `query({ where })` 然后会要求 _每个_ 字段,而不只是关键字段。 要么让所有一般人推断(`new DistributedTable(scope, id, { schema, key, indexes })` 没有明确 `<...>`),或通过所有三个通名. 请注意: `as const` 一个人做 **没有** 修复它.

| 方法 | 回返 | 说明 |
| --- | --- | --- |
| `get(key)` | `Promise<T | null>` | 按主键获取单个项目 . |
| `put(item, options?)` | `Promise<void>` | 存储一个物品。 覆盖, 除非设置条件 . |
| `delete(key, options?)` | `Promise<void>` | 按主键删除项目 . |
| `query(options)` | `AsyncIterable<T>` | 按索引或主键查询项目 . |
| `scan(options?)` | `AsyncIterable<T>` | 完成所有项目。 精通大型数据集. |
| `getBatch(keys)` | `Promise<(T | null)[]>` | 按键获取多个项目 . |
| `putBatch(items)` | `Promise<void>` | 储存多件物品. |
| `deleteBatch(keys)` | `Promise<void>` | 按键删除多个项目 . |
| `DistributedTable.fromExisting(tableName)` | `ExternalTableRef` | 包好先前存在的DynamomDB表格. |

**只有运行时间.** 数据方法`get`, (中文(简体) ), `put`, (中文(简体) ), `delete`, (中文(简体) ), `query`, (中文(简体) ), `scan`, (中文(简体) ), `getBatch`, (中文(简体) ), `putBatch`, (中文(简体) ), `deleteBatch`(按请求时间运行) `ApiNamespace` 方法, `RawRoute` 处理器、工作处理器或运行时脚本, **没有** 在您的顶级 `aws-blocks/index.ts`。顶级代码运行于 CDK 合成期间,其中块解决其基础设施构造,其数据方法为 守护:顶级调用 `Error` 读取 `DistributedTable.<method>() cannot be called during CDK synth. Data methods run at request time — …`。对于种子数据,请从处理器内部或单独的运行时脚本中进行。 在模块范围构造块是好的;只有方法调用才能移动到处理器中.

> **正在收集 `scan()` 结果 :** 喜欢 `query()`, (中文(简体) ), `scan()` 返回一个 `AsyncIterable` - 与 `await Array.fromAsync(table.scan())` 或直线 `for await`. 偏爱 `query()` 结束 `scan()` (扫描仪读取每件物品).

### 选项

| 选项 | 类型 | 需求 | 说明 |
| --- | --- | --- | --- |
| `schema` | `StandardSchemaV1` | 对 | 运行时验证计划(佐德,瓦利博特,ArkType等). 类型 `T` 根据计划推断. |
| `key` | `TableKeyConfig<T>` | 对 | 主密钥配置 : `{ partitionKey, sortKey? }`中必须存在字段名称. |
| `indexes` | `Record<string, TableKeyConfig<T>>` | 没有 | 全球二级指数定义. |
| `ttl` | `keyof T & string` | 没有 | 在指定的属性上启用 DynamoDB TTL 。 字段应当包含以秒计的Unix时间戳. |
| `pointInTimeRecovery` | `boolean | { retentionDays: number }` | 没有 | 即时复苏(接续后援). `true` = 打开默认的35天窗口; `false` =关闭; `{ retentionDays: n }` 继续 `n`\- 日间窗口(**1至35岁**) (中文(简体) ). 堆栈默认值 `defaults.pointInTimeRecovery` (关于 `BlocksPresets.production`关闭在下面 `sandbox`) (中文(简体) ). 每GB-月备份存储的账单;更短的窗口修剪成本. |
| `protection` | `'disposable' | 'retained' | 'locked'` | 没有 | 表格的销毁有多难(spans去除政策+删除保护). `'disposable'` = 随堆栈被删除; `'retained'` = 堆栈删除时成为孤儿,但直接删除仍然有效; `'locked'` =孤儿 **财务报告和审定财务报表** 删除保护。 省略时, 删除策略 + 删除保护跟随堆栈 `defaults` (单位:千美元)`BlocksPresets.production` ≈ `'locked'`, (中文(简体) ), `sandbox` ≈ `'disposable'`) (中文(简体) ). |
| `encryption` | `'aws-managed' | 'customer-managed' | ExternalKmsKeyRef` | 没有 | At -rest 加密密钥. `'aws-managed'` (默认)使用 `aws/dynamodb` KMS 密钥(可审计,无密钥充电); `'customer-managed'` 提供专门的CMK; 通过 `DistributedTable.fromKmsKey(arn)` 以您拥有的现有CMK加密(可跨表格共享). |
| `readValidation` | `'off' | 'coerce' | 'strict'` | 没有 | 如何读取(`get`编号 :`getBatch`编号 :`query`编号 :`scan`将存储的项目与 `schema`。 。 。 . `'coerce'` (单位:千美元)**默认**返回被胁迫值,并在失败时返回原始值+警告(从未丢出); `'strict'` 掷出 `ValidationFailed` 关于不符合同的项目; `'off'` 返回未验证的原始值。 见 [阅读和计划演变](https://npmcn.com/package/%40aws-blocks/bb-distributed-table/#readme-reads-and-schema-evolution)。 。 。 . |
| `table` | `ExternalTableRef` | 没有 | 将已有的 DynamoDB 表格包起来, 而不是创建 。 Durable/加密选项被忽略——客户拥有表格的配置. |
| `logger` | `ChildLogger` | 没有 | 内部操作的可选日志。 省略时, 在警告级别创建默认 Logger `readValidation: 'coerce'` 后退警告浮出水面. |

### 密钥对象模式

所有接受密钥的方法(`get`, (中文(简体) ), `delete`, (中文(简体) ), `getBatch`, (中文(简体) ), `deleteBatch`)用分区键字段取出一个密钥对象(如果定义了,则排序密钥字段)。 密钥类型是从您的策略和密钥配置中计算出来的 —— TypeScript 完全执行正确的字段 :

```typescript
// Table with partition key + sort key
const orders = new DistributedTable(scope, 'orders', {
  schema: orderSchema,
  key: { partitionKey: 'userId', sortKey: 'orderId' },
});

// Key object requires both fields
await orders.get({ userId: 'alice', orderId: '001' });

// Table with partition key only
const settings = new DistributedTable(scope, 'settings', {
  schema: settingsSchema,
  key: { partitionKey: 'settingId' },
});

// Key object requires only the partition key
await settings.get({ settingId: 'theme' });
```

### 查询

`query()` 选择单个选项对象。 指定 `index` 以查询一个GSI,或省略它以查询主键。 这个 `where` 句式是类型安全的——字段名称和条件类型是从索引(或主密钥)定义中计算出来的.

```typescript
// Query a GSI
for await (const order of orders.query({
  index: 'byStatus',
  where: { status: { equals: 'pending' } },
  limit: 10,
  order: 'desc',
})) {
  console.log(order);
}

// Query the primary key (omit index)
for await (const order of orders.query({
  where: { userId: { equals: 'alice' }, orderId: { beginsWith: '2024-' } },
})) {
  console.log(order);
}
```

> **提示 :** 当将所有结果收集到数组时,使用 `Array.fromAsync()` 而不是手动循环 :
> 
> ```typescript
> const pending = await Array.fromAsync(orders.query({
>   index: 'byStatus',
>   where: { status: { equals: 'pending' } },
> }));
> ```

**查询选项 :**

| 外地 | 类型 | 需求 | 说明 |
| --- | --- | --- | --- |
| `index` | `keyof Indexes` | 没有 | GSI 查询 。 关闭查询主密钥 . |
| `where` | `KeyCondition<T, K>` | 对 | 关键条件。 分区密钥需要 `{ equals }`排序密钥支持 `equals`, (中文(简体) ), `greaterThan`, (中文(简体) ), `lessThan`, (中文(简体) ), `between`, (中文(简体) ), `beginsWith`等 (中文(简体) ). |
| `limit` | `number` | 没有 | 要返回的最大项数 . |
| `order` | `'asc' | 'desc'` | 没有 | 排序键的方向 。 默认为 `'asc'`。 。 。 . |

### 有条件的操作

两者 `put` 财务报告和审定财务报表 `delete` 接受可选条件:

```typescript
// Only write if key doesn't exist (idempotent create)
await table.put(item, { ifNotExists: true });

// Only write if existing item's field matches (optimistic locking)
await table.put(updatedItem, { ifFieldEquals: { version: 3 } });

// Only delete if item exists
await table.delete(key, { ifExists: true });

// Only delete if field matches
await table.delete(key, { ifFieldEquals: { status: 'archived' } });
```

所有条件失败 `error.name === DistributedTableErrors.ConditionalCheckFailed`序列化为JSON-RPC **409 (冲突)** 在模拟时间和AWS运行时间, 仅 `ifFieldEquals` 乐观-锁定冲突被标出可以挽回; `ifNotExists` 编号 : `ifExists` 存在断言 **没有** 可回收( 盲重试失败 ) .

> **无部分更新 :** 没有 `update()` 或者说 `patch()` 方法。 要更改字段,请做一个读取-修改-写作—— `get()` 然后改变它 `put()` 整个东西回来。 为安全同步更新, 请通过 `{ ifFieldEquals: { version: <previous> } }` 改为 `put()` 故此写入失败( 通过 `ConditionalCheckFailed`),如果另一个编剧同时更改了项目(乐观地锁定).

### 阅读和计划演变

写作总是以 `schema`。读取根据 **`readValidation`** 选项,此选项在方案更改后很重要:在旧方案下写的行可能不再匹配已宣布的类型 `T` 新增加的一个领域是: **缺席** 从读取( 所以数值沉默地违反) `T`,则a `.default()` 既未适用,也未坚持回函,a **需要,无违约** 字段使上面的读-修改-写周期 **写入失败** 作为 `put()` 拒绝留下的形状.

`readValidation` 有三个模式:

| 模式 | 读取 | 关于一个不符合同的项目 |
| --- | --- | --- |
| **`'coerce'`** (默认) | 返回图中的被强制输出(默认已填充,类型已缩小) | 返回时 **原始内容** 数值 + 记录一个警告 - **从不扔** |
| **`'strict'`** | 对照计划进行验证 | **掷出** `ValidationFailed` |
| **`'off'`** | 返回原始存储值,没有验证 | 返回为-is |

默认 `'coerce'` 关闭计划-进化差距

```typescript
const orderSchema = z.object({
  orderId: z.string(),
  total: z.number(),
  currency: z.string().default('USD'),   // added in a later release
});

const orders = new DistributedTable(scope, 'orders', {
  schema: orderSchema,
  key: { partitionKey: 'orderId' },
  // readValidation: 'coerce' is the default
});

const order = await orders.get({ orderId: 'o1' }); // legacy row → { …, currency: 'USD' }
await orders.put({ ...order, total: 20 });          // round-trips without ValidationFailed
```

**`'coerce'` 从不掷出 :** 返回真正不能被胁迫的值(例如,没有默认要求的字段) **作为** 有警告,所以无法恢复的行 保持可读的迁移和 `get()` 永远不要扔坏一行.

> **最佳强制(验证人-依赖).** 强迫取决于计划 _转换_ 它的投入。 Zod填充默认和铸造;一个只检查的标准Schema验证器(一些Valibot/ArkType schemas)验证而不转换,所以 `'coerce'` 返回这些值的不变值——它从未发明数据.

> **`'coerce'` 保存未在计划内保存的密钥.** 许多计划验证时丢弃未识别的密钥( Zod 对象计划) `.strip()` ——然后,一个被读取的修改-写入会持续丢失。 为了避免这样, `'coerce'` 被逼输出的深渊 **覆盖原始存储项目**: chema 输出赢得每个密钥( 默认被填充, 类型被收缩), 而属性 schema 不声明 —— 从一个更古老的chema 版本, 或列另一个作者拥有的 —— 是 **保留**。阵列被替换为批发(被胁迫阵列获胜),并保留嵌入的未知密钥。 因此,一个例行的读取-修改-写字从不默默地删除一个你没有触及的字段. (使用时) **`'strict'`** 如果你想要一个计划不匹配被拒绝,或者 **`'off'`** 完全跳过计划通过。 )

选择 **`'strict'`** 用于将计划错配视为腐败和拒绝的表格(注:一行坏,然后整个失败) `query`编号 :`scan`编号 :`getBatch`) (中文(简体) ). 选择 **`'off'`** 对于热路径,您所信任的数据是通过此策略写入的,或者读取(并保存)行,您在迁移时尚不能强制.

### 处理错误

分布表所抛出的错误 `error.name` 您可以与 `isBlocksError`数字 :

| 常数 | `error.name` | 掷出时 |
| --- | --- | --- |
| `DistributedTableErrors.ConditionalCheckFailed` | `ConditionalCheckFailedException` | 一个 `ifNotExists` 编号 : `ifExists` 编号 : `ifFieldEquals` 条件失败 。 序列化为 HTTP **409 (冲突)**; 仅用于 `ifFieldEquals` 乐观冲突(不是) `ifNotExists` 编号 : `ifExists`) (中文(简体) ). |
| `DistributedTableErrors.ValidationFailed` | `ValidationFailedException` | 已配置的项目失败 `schema` 验证时间 `put()` 编号 : `putBatch()`。 。 。 . |
| `DistributedTableErrors.InvalidQuery` | `InvalidQueryException` | 查询/条件形状错误: 缺失 `where`,未给出分区键为 `{ equals }`,未知索引,多排序条件,或空 `ifFieldEquals`呼叫器错误. |
| `DistributedTableErrors.ItemTooLarge` | `ItemTooLargeException` | A 类 `put`编号 :`putBatch` 超过 DynamoDB 400 KB 的每个项目大小限制. |
| `DistributedTableErrors.BatchIncomplete` | `BatchIncompleteException` | 批量操作在重试预算( 持续节奏) 后未处理条目 。 AWS只运行时间 . |

```typescript
import { isBlocksError } from '@aws-blocks/core';
import { DistributedTableErrors } from '@aws-blocks/bb-distributed-table';

try {
  await table.put(item, { ifNotExists: true });
} catch (e: unknown) {
  if (isBlocksError(e, DistributedTableErrors.ConditionalCheckFailed)) {
    // item already exists
  }
  if (isBlocksError(e, DistributedTableErrors.ItemTooLarge)) {
    // item > 400 KB — split it or store a reference instead
  }
  throw e;
}
```

## 实例

### 基础 CROUD

> 这些例子使用Zod,但 `schema` 接受任何标准SchemaV1执行(Zod, Valibot, ArkType). 安装您选择的库, 例如 . `npm install zod`。 。 。 .

```typescript
import { z } from 'zod';

const orderSchema = z.object({
  userId: z.string(),
  orderId: z.string(),
  total: z.number(),
  status: z.string(),
  createdAt: z.number(),
});

const orders = new DistributedTable(scope, 'orders', {
  schema: orderSchema,
  key: { partitionKey: 'userId', sortKey: 'orderId' },
});

export const api = new ApiNamespace(scope, 'api', (context) => ({
  async getOrder(userId: string, orderId: string) {
    return await orders.get({ userId, orderId });
  },
  async createOrder(order: z.infer<typeof orderSchema>) {
    await orders.put(order, { ifNotExists: true });
  },
  async deleteOrder(userId: string, orderId: string) {
    await orders.delete({ userId, orderId });
  },
}));
```

### 以按键排序条件查询

```typescript
const orders = new DistributedTable(scope, 'orders', {
  schema: orderSchema,
  key: { partitionKey: 'userId', sortKey: 'orderId' },
  indexes: {
    byDate: { partitionKey: 'userId', sortKey: 'createdAt' },
  },
});

// Ctrl+Space on the where object shows: userId, createdAt
// userId requires { equals }, createdAt supports greaterThan, between, etc.
const results = [];
for await (const order of orders.query({
  index: 'byDate',
  where: {
    userId: { equals: 'alice' },
    createdAt: { greaterThan: Date.now() - 86400000 },
  },
})) {
  results.push(order);
}
```

### TTL( 自动过期项目)

```typescript
const sessions = new DistributedTable(scope, 'sessions', {
  schema: sessionSchema,
  key: { partitionKey: 'sessionId' },
  ttl: 'expiresAt',
});

// DynamoDB automatically deletes items after the TTL timestamp
await sessions.put({
  sessionId: 'abc123',
  userId: 'alice',
  expiresAt: Math.floor(Date.now() / 1000) + 3600, // 1 hour from now
});
```

### 批量操作

```typescript
// Write many items
await orders.putBatch([order1, order2, order3]);

// Read many items
const items = await orders.getBatch([
  { userId: 'alice', orderId: '001' },
  { userId: 'bob', orderId: '002' },
]);

// Delete many items
await orders.deleteBatch([
  { userId: 'alice', orderId: '001' },
  { userId: 'bob', orderId: '002' },
]);
```

### 环绕已存在的表格

```typescript
const legacy = new DistributedTable(scope, 'legacy', {
  schema: orderSchema,
  key: { partitionKey: 'userId', sortKey: 'orderId' },
  table: DistributedTable.fromExisting('my-existing-table'),
});
```

## 最佳做法

-   为偶数数据分布设计分区键(例如, `userId`, (中文(简体) ), `tenantId`(中文(简体) )
-   对范围查询使用排序键(例如:时间戳、字母顺序)
-   定义已知访问模式的 GSIs 前置 —— 以后添加它们需要回填
-   使用 `{ ifNotExists: true }` 用于生成偶数
-   使用 `{ ifFieldEquals }` 当多个作者有可能时, 乐观的锁定
-   偏爱 `query()` 结束 `scan()` ——扫描每件物品,价格昂贵

## 缩放成本( AWS)

-   **计费:** PAY PER REQENT - 没有提供管理能力
-   **延迟 :** 读取和写出数位数
-   **通过量 :** 自动缩放, 表格大小无上限
-   **项目大小限制 :** 每件400KB
-   **GSI 限制 :** 每表最多20个全球二级指数
-   **费用:** ~每百万人有1.25美元,~每百万人有0.25美元
-   **重复性 :** 99.99999999999%(119%),跨越3个AZ

## 重复和安全默认( S)

疲惫的姿势来自 **堆栈宽度 `BlocksDefaults`** 交给你 `BlocksStack.create` 编号 : `BlocksBackend.create` (单位:千美元)`BlocksPresets.production` 或者说 `BlocksPresets.sandbox` 从 `@aws-blocks/core/cdk`)——每块建筑块都读取同样的取号,所以一张表格的去除政策,去除保护,以及连续备份姿态都跟随了应用程序所选择的预设. 没有每个街区 `sandboxMode` 猜测.

下 **`BlocksPresets.production`**,每个表格中,本块规定船舶:

-   **即时恢复** 启用( e)`defaults.pointInTimeRecovery`)——在过去35天恢复到任何一秒.
-   **保留 + 删除保护** (单位:千美元)`defaults.removalPolicy = RETAIN`, (中文(简体) ), `defaults.deletionProtection = true`)——既无倒叠倒地,也无流浪 `cdk destroy`/收音机删除可以擦去桌子,直到明确放松. (相当于 `protection: 'locked'`. ) (中文(简体) )
-   **SSE - KMS (英语)** 由AWS管理 `aws/dynamodb` 密钥 – 可通过 CloudTrail 进行验证的加密- rest 可不按每键收费.

下 **`BlocksPresets.sandbox`** 换个方式,PITR关闭, `RemovalPolicy.DESTROY`,删除保护(相当于 `protection: 'disposable'`)——所以丢弃的堆栈保持廉价并 `sandbox:destroy` 是一个命令撕毁。 SSE-KMS 都保留在其中(加密不属于 `BlocksDefaults` 每块选项默认为 `aws-managed`) (中文(简体) ).

> **PITR不是免费的.** 连续备份存储的点-点-点-点-点-点-点-点-点-点-点-点-点-点-点-点-点-点-点-点-点-点-点-点-点-点-点-点-点-点-点-点-点-点-点-点-点-点-点-点-点-点-点-点-点-点-点-点-点-点-点-点-点-点-点-点-点-点-点-点-点-点-点-点-点-点-点-点-点-点-点-点-点-点-点-点-点-点-点-点-点-点-点-点-点-点-点-点-点-点-点-点-点-点-点-点-点-点-点-点-点-点-点-点-点-点-点-点-点-点-点-点-点-点-点-点-点-点-点-点-点-点-点-点-点-点 它是默认的,因为无法恢复的数据损失通常是更糟糕的结果——但对于可再生的数据(caches,衍生表格)集 `pointInTimeRecovery: false`。 。 。 .

> **`protection: 'locked'`编号 :`'retained'` 孤体,堆栈删除的表格.** 因为驱逐政策是 `RETAIN`,删除堆栈后留下表格(通过设计——您的数据存活)。 但表格名称是从区块的ID中衍生出来的 所以 **后调用同一应用程序失败 `Table already exists`** 直到你们删除已忽略的表格`aws dynamodb delete-table`中,如果 `'locked'`)或导入到新堆栈中。 这是保留在删除中固有的;使用 `protection: 'disposable'` 对于您期望可以自由重现的表格.

> **索引跟随配置,而表格则在堆栈中.** 删除一个索引(或整个) `indexes` 选项),从您的配置中并重新部署从表格中跳出。 当表格本身离开堆栈时(您删除堆栈,或去掉 `DistributedTable` 它的索引是孤寡的 `'locked'`编号 :`'retained'` 表格保存全部,所以导入到新堆栈不需要重建索引。 要告诉两者分开,GSI管理器读取了堆栈的模板. 如果在更新(或回滚更新)的清理阶段无法读取该索引,则该索引保持不变,并报告 `DELETE_FAILED` 用于表格的 GSI 自定义资源的事件(逻辑 ID 包含 `gsiresource`来命名表格和索引。 部署本身仍然成功,所以检查该事件的部署输出(或堆栈事件). 要删除您已经没有的索引, 运行 `aws dynamodb update-table --table-name <table> --global-secondary-index-updates '[{"Delete":{"IndexName":"<index>"}}]'`; DynamoDB每次呼叫需要一个索引变化,所以等待每个删除在下个之前完成.

每个堆栈默认值每个表都是压倒性的(每块选项总是胜过) `defaults`:

```typescript
// Cost-sensitive prod table: keep it protected, skip PITR's backup cost
const cache = new DistributedTable(scope, 'cache', {
  schema, key: { partitionKey: 'id' },
  pointInTimeRecovery: false,
});

// Long-lived data you still want to be able to delete directly
const staging = new DistributedTable(scope, 'staging', {
  schema, key: { partitionKey: 'id' },
  protection: 'retained',   // survives stack delete, but not deletion-protected
});

// Compliance-strict table: dedicated customer-managed KMS key
const ledger = new DistributedTable(scope, 'ledger', {
  schema, key: { partitionKey: 'id' },
  encryption: 'customer-managed',
});

// Share one customer-managed key across several tables (one key, one bill)
const key = DistributedTable.fromKmsKey('arn:aws:kms:us-east-1:111122223333:key/abcd-1234');
const orders = new DistributedTable(scope, 'orders', {
  schema, key: { partitionKey: 'id' },
  encryption: key,
});
const events = new DistributedTable(scope, 'events', {
  schema, key: { partitionKey: 'id' },
  encryption: key,
});
```

> 压倒性总是会战胜环境默认,这样你就可以在沙盒中(或放轻松一分)明确强制一个完全耐用,受保护的桌子. 当你通过自己的桌子 `fromExisting()`,这些选项都不适用——您拥有该表的配置.

> **`customer-managed` 每表提供专用CMK** ——一款配有十几张客户管理表的应用程序获得一打KMS密钥(~每个月1美元,外加请求费). 要在多个表格中共享一个密钥, 请创建一个密钥并传递 `DistributedTable.fromKmsKey(keyArn)` 作为 `encryption` 选项。 使用默认 `'aws-managed'` 除非表格需要自己的旋转/关键政策控制.

## 地方发展

模拟数据持续到磁盘 `.bb-data/{fullId}/` 跨 Dev 服务器重启 。 擦拭为 `rm -rf .bb-data`。模拟验证了400 KB 项的尺寸限制、 计划验证以及有条件的检查失败, 符合 AWS 行为。 索引查询是通过内膜过滤执行的——正确性得到保留,但性能特征与DynamoDB不同.

## 常见问题

### @aws-blocks/bb-distributed-table 是什么？

结构化数据存储由DynamoDB支持,具有二级索引和丰富的查询能力\.

### 如何安装 @aws-blocks/bb-distributed-table？

在项目目录运行 npm install @aws-blocks/bb-distributed-table，或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖：constructs（^10\.6\.0）、aws-cdk-lib（^2\.257\.0）。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖，Yarn 需要手动安装。

### @aws-blocks/bb-distributed-table 支持 TypeScript 吗？

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

### @aws-blocks/bb-distributed-table 支持 ESM 还是 CommonJS？

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

### @aws-blocks/bb-distributed-table 可以商用吗？

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

### @aws-blocks/bb-distributed-table 的下载量有多少？

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

### @aws-blocks/bb-distributed-table 还在维护吗？

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

