

# DynamoDB 中的定期付款架构设计
<a name="data-modeling-schema-recurring-payments"></a>

## 定期付款业务使用场景
<a name="data-modeling-schema-recurring-payments-use-case"></a>

这个使用场景讨论了如何使用 DynamoDB 来实现定期付款系统。数据模型具有以下实体：*账户*、*订阅*以及*收据*。我们的使用场景的具体内容包括以下各项：
+ 每个*账户*可以有多个*订阅*
+ 当需要处理下一笔付款时，*订阅*具有 `NextPaymentDate`；当向客户发送电子邮件提醒时，则具有 `NextReminderDate`
+ *订阅*有一个项目，此项目在处理付款时存储并更新（平均项目大小约为 1KB，吞吐量取决于*账户*和*订阅*的数量）
+ *付款*处理器还将创建*收据*作为此过程的一部分，该收据存储在表中，并通过使用 [TTL](TTL.md) 属性设置为在一段时间后过期

## 定期付款实体关系图
<a name="data-modeling-schema-recurring-payments-erd"></a>

这是我们将为定期付款系统架构设计使用的实体关系图（ERD）。

![\[定期付款系统 ERD 显示实体：Account、Subscription 和 Receipt。\]](http://docs.aws.amazon.com/zh_cn/amazondynamodb/latest/developerguide/images/DataModeling/ReoccurringPayments-1-ERD.png)


## 定期付款系统访问模式
<a name="data-modeling-schema-recurring-payments-access-patterns"></a>

这些是我们将为定期付款系统架构设计考虑的访问模式。

1. `createSubscription`

1. `createReceipt`

1. `updateSubscription`

1. `getDueRemindersByDate`

1. `getDuePaymentsByDate`

1. `getSubscriptionsByAccount`

1. `getReceiptsByAccount`

## 定期付款架构设计
<a name="data-modeling-schema-recurring-payments-design-evolution"></a>

通用名称 `PK` 和 `SK` 用于键属性，以允许在同一个表中存储不同类型的实体，例如账户、订阅和收款实体。用户首先创建订阅，即用户同意在每个月的同一天支付一定金额以换取产品。他们可以选择在一个月的哪一天处理付款。在处理付款之前，还会发送提醒。该应用程序的工作原理是每天运行两个批处理任务：一个批处理任务发送当天到期的提醒，另一个批处理任务处理当天到期的任何付款。

**步骤 1：解决访问模式 1 (`createSubscription`)**

访问模式 1（`createSubscription`）用于最初创建订阅，并设置详细信息，包括 `SKU`、`NextPaymentDate`、`NextReminderDate` 和 `PaymentDetails`。此步骤仅显示一个账户（具有一个订阅）的表状态。项目集合中可能有多个订阅，因此这是一种一对多关系。

![\[这一表设计显示账户的订阅详细信息。\]](http://docs.aws.amazon.com/zh_cn/amazondynamodb/latest/developerguide/images/DataModeling/ReoccurringPayments-2-Step1.png)


**步骤 2：解决访问模式 2（`createReceipt`）和 3（`updateSubscription`)**

访问模式 2（`createReceipt`）用于创建收据项目。每月处理付款后，付款处理器会将收据写回基表。项目集合中可能有多张收据，因此这是一对多关系。付款处理器还将更新订阅项目 [访问模式 3（`updateSubscription`)]，以针对下个月的 `NextReminderDate` 或 `NextPaymentDate` 进行更新。

![\[收据详细信息和订阅项目更新，来显示下一个订阅提醒日期。\]](http://docs.aws.amazon.com/zh_cn/amazondynamodb/latest/developerguide/images/DataModeling/ReoccurringPayments-3-Step2.png)


**步骤 3：解决访问模式 4（`getDueRemindersByDate`）**

该应用程序会分批处理当天的付款提醒。因此，应用程序需要在不同的维度上访问订阅：日期而不是账户。这是[全局二级索引（GSI）](GSI.md)的一个很好的使用场景。在此步骤中，我们添加索引 `GSI-1`，它使用 `NextReminderDate` 作为 GSI 分区键。我们不需要复制所有项目。此 GSI 是一个[稀疏索引](data-modeling-blocks.md#data-modeling-blocks-sparse-index)，并且未复制收据项目。我们也不需要投影所有属性 — 我们只需要包含属性的子集。下图显示了 `GSI-1` 的架构，它提供了应用程序发送提醒电子邮件所需的信息。

![\[此 GSI-1 架构包含电子邮件地址等详细信息，应用程序需要这些信息来发送提醒电子邮件。\]](http://docs.aws.amazon.com/zh_cn/amazondynamodb/latest/developerguide/images/DataModeling/ReoccurringPayments-4-Step3.png)


**步骤 4：解决访问模式 5（`getDuePaymentsByDate`）**

该应用程序以与对待提醒相同的方式批处理当天的付款。我们在此步骤中添加 `GSI-2`，它使用 `NextPaymentDate` 作为 GSI 分区键。我们不需要复制所有项目。此 GSI 是一个稀疏索引，因为未复制收据项目。下图显示了 `GSI-2` 的架构。

![\[此 GSI-2 架构包含处理付款的详细信息。NextPaymentDate 是 GSI-2 的分区键。\]](http://docs.aws.amazon.com/zh_cn/amazondynamodb/latest/developerguide/images/DataModeling/ReoccurringPayments-5-Step4.png)


**步骤 5：解决访问模式 6（`getSubscriptionsByAccount`）和 7（`getReceiptsByAccount`）**

应用程序可以通过对以账户标识符（`PK`）为目标的基表使用[查询](Query.md)来检索账户的所有订阅，并使用范围运算符来获取 `SK` 以“SUB\$1”开头的所有项目。应用程序还可以使用相同的查询结构来检索所有收据，方法是使用范围运算符来获取其中 `SK` 以“REC\$1”开头的所有收据。这使我们能够满足访问模式 6（`getSubscriptionsByAccount`）和 7（`getReceiptsByAccount`）的要求。应用程序使用这些访问模式，因此，用户可以查看他们当前的订阅和过去六个月的收据。在此步骤中，表架构没有发生任何变化，我们可以在下面看到我们如何仅将访问模式 6（`getSubscriptionsByAccount`）中的订阅项目作为目标。

![\[对基表执行查询操作的结果。它显示特定账户的订阅。\]](http://docs.aws.amazon.com/zh_cn/amazondynamodb/latest/developerguide/images/DataModeling/ReoccurringPayments-6-Step5.png)


下表总结了所有访问模式以及架构设计如何解决访问模式：


| 访问模式 | 基表/GSI/LSI | 操作 | 分区键值 | 排序键值 | 
| --- | --- | --- | --- | --- | 
| createSubscription | 基表 | PutItem | ACC\$1account\$1id | SUB\$1<SUBID>\$1SKU<SKUID> | 
| createReceipt | 基表 | PutItem | ACC\$1account\$1id | REC\$1<RecieptDate>\$1SKU<SKUID> | 
| updateSubscription | 基表 | UpdateItem | ACC\$1account\$1id | SUB\$1<SUBID>\$1SKU<SKUID> | 
| getDueRemindersByDate | GSI-1 | 查询 | <NextReminderDate> |  | 
| getDuePaymentsByDate | GSI-2 | 查询 | <NextPaymentDate> |  | 
| getSubscriptionsByAccount | 基表 | Query | ACC\$1account\$1id | SK begins\$1with “SUB\$1” | 
| getReceiptsByAccount | 基表 | Query | ACC\$1account\$1id | SK begins\$1with “REC\$1” | 

## 定期付款最终架构
<a name="data-modeling-schema-recurring-payments-final-schema"></a>

这是最终的架构设计。要以 JSON 文件格式下载此架构设计，请参阅 GitHub 上的 [DynamoDB 示例](https://github.com/aws-samples/aws-dynamodb-examples/blob/master/schema_design/SchemaExamples/ReocurringPayments/ReocurringPaymentsSchema.json)。

**基表**

![\[此基表设计显示账户信息及其订阅和收据详细信息。\]](http://docs.aws.amazon.com/zh_cn/amazondynamodb/latest/developerguide/images/DataModeling/ReoccurringPayments-7-Base.png)


**GSI-1**

![\[此 GSI-1 架构包含订阅详细信息，例如电子邮件地址和 NextPaymentDate。\]](http://docs.aws.amazon.com/zh_cn/amazondynamodb/latest/developerguide/images/DataModeling/ReoccurringPayments-8-GSI1.png)


**GSI-2**

![\[此 GSI-2 架构包含付款详细信息，例如 PaymentAmount 和 PaymentDay。\]](http://docs.aws.amazon.com/zh_cn/amazondynamodb/latest/developerguide/images/DataModeling/ReoccurringPayments-9-GSI2.png)


## 在此架构设计中使用 NoSQL Workbench
<a name="data-modeling-schema-recurring-payments-nosql"></a>

若要进一步探索和编辑新项目，您可以将此最终架构导入到 [NoSQL Workbench](workbench.md)，这是一款为 DynamoDB 提供数据建模、数据可视化和查询开发功能的可视化工具。请按照以下步骤开始使用：

1. 下载 NoSQL Workbench。有关更多信息，请参阅 [下载 NoSQL Workbench for DynamoDB](workbench.settingup.md)。

1. 下载上面列出的 JSON 架构文件，该文件已经采用 NoSQL Workbench 模型格式。

1. 将 JSON 架构文件导入到 NoSQL Workbench。有关更多信息，请参阅 [导入现有数据模型](workbench.Modeler.ImportExisting.md)。

1. 导入到 NOSQL Workbench 后，您便可编辑数据模型。有关更多信息，请参阅 [编辑现有数据模型](workbench.Modeler.Edit.md)。