本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。
使用扩展
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
每次成功将项目写入数据库时,AutoGeneratedTimestampRecordExtension
都会自动使用当前时间戳更新类型为 Instant
的已标记属性。
默认情况下不加载此扩展。因此,在构建增强型客户端时,您需要将其指定为自定义扩展,如本主题的第一个示例所示。
要指定将使用当前时间戳更新的属性,请在表架构中标记 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())
AutoGeneratedUuidExtension
当向数据库写入新记录时,您可以使用为属性生成唯一的UUID(通用唯一标识符)AutoGeneratedUuidExtension
java.lang.String
属性。
由于 Java 默认情况下SDK不加载此扩展,因此您需要在构建增强型客户端时将其指定为自定义扩展,如本主题的第一个示例所示。
该uniqueId
属性是以下代码段中扩展程序行为的目标。
@AutoGeneratedUuidExtension public String getUniqueId() {...} public void setUniqueId(String uniqueId) {...}
下面的代码段显示了等效的静态表架构方法。
.addAttribute(String.class, a -> a.name("uniqueId") .getter(Customer::getUniqueId) .setter(Customer::setUniqueId) // Applying the 'autoGeneratedUuid' tag to the attribute. .tags(AutoGeneratedUuidExtension.AttributeTags.autoGeneratedUuidAttribute())
如果您希望扩展UUID仅为putItem
方法填充而不是方法,请添加更新行为updateItem
@AutoGeneratedUuidExtension @DynamoDbUpdateBehavior(UpdateBehavior.WRITE_IF_NOT_EXISTS) public String getUniqueId() {...} public void setUniqueId(String uniqueId) {...}
如果您使用静态表架构方法,请使用以下等效代码。
.addAttribute(String.class, a -> a.name("uniqueId") .getter(Customer::getUniqueId) .setter(Customer::setUniqueId) // Applying the 'autoGeneratedUuid' tag to the attribute. .tags(AutoGeneratedUuidExtension.AttributeTags.autoGeneratedUuidAttribute(), StaticAttributeTags.updateBehavior(UpdateBehavior.WRITE_IF_NOT_EXISTS))
自定义扩展
以下自定义扩展类显示了使用更新表达式的 beforeWrite()
方法。在注释行 2 之后,如果数据库中的项目还没有 registrationDate
属性,我们会创建一个 SetAction
来设置 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 WriteModification.builder().build(); // Return an "empty" WriteModification instance if the extension should not be applied. // In this case, if the code is not updating an item on the Customer table. } 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(); } }