

本文属于机器翻译版本。若本译文内容与英语原文存在差异，则一律以英文原文为准。

# 缓存写入行为
<a name="cache-write"></a>

本指南描述了一种直读缓存，其中项目在首次读取时会被缓存。在写入操作期间，直写缓存会将条目推送到缓存中，但本指南不建议这样做，原因有两个：
+ 写入项目时，没有迹象表明它很快就会被读取，写入未使用的缓存条目也是一种浪费。
+ 缓存的项目可能会在不同的签名密钥下多次缓存。例如，不同的投影表达式会生成不同的缓存条目。因此，在请求传入之前，尚不清楚应将条目存储在哪个签名密钥下。您可能会认为仅将项目全部缓存一次，而且，如果请求指定了`ProjectionExpression`参数，则在缓存包装器中实时应用投影。不幸的是，这大大增加了复杂性，因为它需要实现非平凡`ProjectionExpression`的语法。保持缓存包装器非常简单会更容易，因此它只缓存以前发生的请求，并尽量避免发明新的响应。让数据库成为`ProjectionExpression`唯一被解释的地方。这就消除了简单的直写式缓存模型。

但是，写入操作可以是智能的，它们可以主动使之前存储的与写入项目相关的任何项目缓存条目失效。这样可以使项目缓存保持最新状态，而不必等待 TTL 到期。缓存条目将在下次读取时重新填充。

**注意**  
与设计相似的关系数据库缓存集成相比，这种 DynamoDB 集成的一个关键优势是，每次写入 DynamoDB 时始终指定正在写入的项目的主键。直读缓存可以监视写入调用并立即执行精确的项目缓存失效。当你使用关系数据库时，`UPDATE`语句无法识别可能受到影响的项目，除了通过 TTL 之外，没有其他被动的方法可以使缓存的行条目失效。

写入调用实现以下逻辑流程：
+ 对数据库执行写入操作。
+ 如果操作成功，请提取表和主键进行写入。
+ 使所有与主键相关的项目缓存条目无效。

要使最后一步成为可能，需要进行一些内部整理。项目缓存条目存储在其签名的哈希值下，因此有必要知道哪些密钥要失效。为此，可以在缓存中维护项目主键和与该主键关联的存储签名列表之间的映射。正是那份必须失效的物品清单。

这是之前的表格：


| 伪码 | ElastiCache 密钥计算 | ElastiCache 价值 | 
| --- | --- | --- | 
| `get_item(t1, k1, p1)` | `hash('get', t1, k1, p1) = 0xad4c812a` | `{ 'Item': … }` | 
| `get_item(t1, k1, p2)` | `hash('get', t1, k2, p2) = 0x045deaab` | `{ 'Item': … }` | 
| `get_item(t1, k2, p1)` | `hash('get', t1, k2, p1) = 0x9cda78af` | `{ 'Item': … }` | 

还有之前的客房清洁表：


| 操作 | ElastiCache 密钥计算 | ElastiCache 价值 | 
| --- | --- | --- | 
| 跟踪表`t1`、键的条目列表 `k1` | `hash('list', t1, k1)` | ( `0xad4c812a, 0x045deaab` ) | 
| 跟踪表`t1`、键的条目列表 `k2` | `hash('list', t1, k2) ` | ( `0x9cda78af` ) | 

假设对表进行了写入操作，`t1`并且该项目具有主键`k1`。下一步是使与该项目相关的条目失效。

以下是完整的逻辑：
+ 对数据库执行写入操作。
+ 如果操作成功，请提取表和主键进行写入。
+ 从缓存中提取与该主键关联的存储哈希签名的列表。
+ 使这些项目缓存条目无效。
+ 删除该主键的管理列表。

如果能有一种方法在项目写入操作中主动使查询缓存条目失效，那就太棒了。但是，为此发明设计极其困难，因为几乎不可能高效、可靠地确定哪些缓存的查询结果会受到更新的项目的影响。因此，查询缓存条目没有比通过 TTL 设置过期更好的选择了。