本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。
扩展
DynamoDB 增强型客户端 API 支持提供映射操作以外的功能的插件扩展。扩展有两种挂接方法,beforeWrite()
和afterRead()
。 beforeWrite()
在写入操作发生之前对其进行修改,该afterRead()
方法在读取操作发生后修改读取操作的结果。由于某些操作(例如项目更新)先执行写入和读取,因此两种挂接方法都会被调用。
扩展按照增强型客户端生成器中指定的顺序加载。加载顺序可能很重要,因为一个扩展可以作用于先前扩展已转换的值。
增强型客户端 API 附带了一组位于extensions
包中的插件扩展。默认情况下,增强型客户端会加载VersionedRecordExtension
和AtomicCounterExtension
。您可以使用增强客户端生成器覆盖默认行为并加载任何扩展。如果您不想要默认扩展名,也可以指定无。
如果您加载自己的扩展,则增强版客户端不会加载任何默认扩展。如果您想要任一默认扩展提供的行为,则需要将其明确添加到扩展列表中。
在以下示例中,名为verifyChecksumExtension
的自定义扩展在后面加载VersionedRecordExtension
,该扩展通常是默认情况下自行加载的。在本示例中未加载。AtomicCounterExtension
DynamoDbEnhancedClientExtension versionedRecordExtension = VersionedRecordExtension.builder().build(); DynamoDbEnhancedClient enhancedClient = DynamoDbEnhancedClient.builder() .dynamoDbClient(dynamoDbClient) .extensions(versionedRecordExtension, verifyChecksumExtension) .build();
VersionedRecordExtension
默认情况下会加载,在项目写入数据库时,它将增加并跟踪项目的版本号。VersionedRecordExtension
如果实际持久项目的版本号与应用程序上次读取的值不匹配,则每次写入都会添加一个条件,导致写入失败。这种行为有效地为项目更新提供了乐观的锁定。如果另一个进程在第一个进程读取项目和正在向其写入更新之间更新该项目,则写入将失败。
要指定使用哪个属性来跟踪项目版本号,请在表架构中标记数字属性。
以下代码段指定该version
属性应保存项目版本号。
@DynamoDbVersionAttribute public Integer getVersion() {...}; public void setVersion(Integer version) {...};
等效的静态表架构方法如以下片段所示。
.addAttribute(Integer.class, a -> a.name("version") .getter(Customer::getVersion) .setter(Customer::setVersion) // Apply the 'version' tag to the attribute. .tags(VersionedRecordExtension.AttributeTags.versionAttribute())
AtomicCounterExtension
默认情况下会AtomicCounterExtension
加载,每次将记录写入数据库时都会增加带标签的数字属性。可以指定起始值和增量值。如果未指定任何值,则将起始值设置为 0,该属性的值增加 1。
要指定哪个属性是计数器,请在表架构Long
中标记类型的属性。
以下代码段显示了该属性的默认起始值和增量值的counter
使用。
@DynamoDbAtomicCounter public Long getCounter() {...}; public void setCounter(Long counter) {...};
以下代码段显示了静态表架构方法。原子计数器扩展使用起始值 10,并在每次写入记录时将该值增加 5。
.addAttribute(Integer.class, a -> a.name("counter") .getter(Customer::getCounter) .setter(Customer::setCounter) // Apply the 'atomicCounter' tag to the attribute with start and increment values. .tags(StaticAttributeTags.atomicCounter(10L, 5L))
AutoGeneratedTimestampRecordExtension
每次将项目成功写入数据库时Instant
,都会AutoGeneratedTimestampRecordExtension
自动使用当前时间戳更新类型的标记属性。
默认情况下,此扩展程序未加载。因此,在构建增强型客户端时,需要将其指定为自定义扩展,如本主题的第一个示例所示。
要指定使用当前时间戳更新哪个属性,请在表架构中标记该Instant
属性。
该lastUpdate
属性是以下代码片段中扩展行为的目标。请注意,要求该属性必须是Instant
类型。
@DynamoDbAutoGeneratedTimestampAttribute public Instant getLastUpdate() {...} public void setLastUpdate(Instant lastUpdate) {...}
等效的静态表架构方法如以下片段所示。
.addAttribute(Instant.class, a -> a.name("lastUpdate") .getter(Customer::getLastUpdate) .setter(Customer::setLastUpdate) // Applying the 'autoGeneratedTimestamp' tag to the attribute. .tags(AutoGeneratedTimestampRecordExtension.AttributeTags.autoGeneratedTimestampAttribute())
自定义扩展
以下自定义扩展类显示了使用更新表达式beforeWrite()
的方法。在注释第 2 行之后SetAction
,如果数据库中的项目还没有registrationDate
属性,我们将创建一个来设置该registrationDate
属性。每当更新Customer
对象时,扩展都会确保设置registrationDate
了。
public final class CustomExtension implements DynamoDbEnhancedClientExtension { // 1. In a custom extension, use an UpdateExpression to define what action to take before // an item is updated. @Override public WriteModification beforeWrite(DynamoDbExtensionContext.BeforeWrite context) { if ( context.operationContext().tableName().equals("Customer") && context.operationName().equals(OperationName.UPDATE_ITEM)) { return WriteModification.builder() .updateExpression(createUpdateExpression()) .build(); } return null; } private static UpdateExpression createUpdateExpression() { // 2. Use a SetAction, a subclass of UpdateAction, to provide the values in the update. SetAction setAction = SetAction.builder() .path("registrationDate") .value("if_not_exists(registrationDate, :regValue)") .putExpressionValue(":regValue", AttributeValue.fromS(Instant.now().toString())) .build(); // 3. Build the UpdateExpression with one or more UpdateAction. return UpdateExpression.builder() .addAction(setAction) .build(); } }