Uso de extensiones para personalizar operaciones de DynamoDB Enhanced Client
La API del cliente mejorado de DynamoDB admite extensiones de complementos que proporcionan funciones que van más allá de las operaciones de mapeo. Las extensiones utilizan dos métodos de enlace para modificar datos durante las operaciones de lectura y escritura:
beforeWrite(): modifica una operación de escritura antes de que se produzcaafterRead(): modifica los resultados de una operación de lectura después de que se produzca
Algunas operaciones (como las actualizaciones de elementos) realizan una escritura y luego una lectura, por lo que se llama a ambos métodos de enlace.
Cómo se cargan las extensiones
Las extensiones se cargan en el orden que especifique en el compilador del cliente mejorado. El orden de carga puede ser importante porque una extensión puede actuar sobre valores que han sido transformados por una extensión anterior.
De forma predeterminada, el cliente mejorado carga dos extensiones:
VersionedRecordExtension: proporciona bloqueo positivoAtomicCounterExtension: incrementa automáticamente los atributos del contador
Puede anular el comportamiento predeterminado con el compilador del cliente mejorado y cargar cualquier extensión. También puede no especificar ninguna si no desea utilizar las extensiones predeterminadas.
importante
Si carga sus propias extensiones, el cliente mejorado no carga ninguna extensión predeterminada. Si desea el comportamiento proporcionado por alguna de las extensiones predeterminadas, deberá añadirla explícitamente a la lista de extensiones.
El siguiente ejemplo muestra cómo cargar una extensión personalizada llamada verifyChecksumExtension después de la VersionedRecordExtension. La AtomicCounterExtension no se carga en este ejemplo.
DynamoDbEnhancedClientExtension versionedRecordExtension = VersionedRecordExtension.builder().build(); DynamoDbEnhancedClient enhancedClient = DynamoDbEnhancedClient.builder() .dynamoDbClient(dynamoDbClient) .extensions(versionedRecordExtension, verifyChecksumExtension) .build();
Detalles y configuración de extensión disponibles
En las secciones siguientes se proporciona información detallada sobre cada extensión disponible en el SDK.
Implemente bloqueo positivo con VersionedRecordExtension
La extensión VersionedRecordExtension proporciona bloqueo positivo incrementando y rastreando el número de versión de los elemento a medida que estos se escriben en la base de datos. Se añade una condición a cada escritura que hará que esta falle si el número de versión del elemento persistido real no coincide con el valor que la aplicación leyó por última vez.
Configuración
Para especificar qué atributo usar para rastrear el número de versión del elemento, etiquete un atributo numérico en el esquema de la tabla.
El siguiente fragmento especifica que el atributo version debe contener el número de versión del artículo.
@DynamoDbVersionAttribute public Integer getVersion() {...}; public void setVersion(Integer version) {...};
El enfoque equivalente del esquema de tabla estático se muestra en el siguiente fragmento.
.addAttribute(Integer.class, a -> a.name("version") .getter(Customer::getVersion) .setter(Customer::setVersion) // Apply the 'version' tag to the attribute. .tags(VersionedRecordExtension.AttributeTags.versionAttribute())
Funcionamiento
El bloqueo positivo con la VersionedRecordExtension tiene el siguiente efecto en estos métodos DynamoDbEnhancedClient y DynamoDbTable.
putItem-
A los nuevos elementos se les asigna un valor de versión inicial de 0. Esto se puede configurar con
@DynamoDbVersionAttribute(startAt =.X) updateItem-
Si recupera un elemento, actualiza una o varias de sus propiedades e intenta guardar los cambios, la operación solamente se lleva a cabo si el número de versión del lado del cliente coincide con el número de versión del lado del servidor.
Si la operación es correcta, el número de versión aumenta automáticamente en 1. Esto se puede configurar con
@DynamoDbVersionAttribute(incrementBy =.X) deleteItem-
La anotación
DynamoDbVersionAttributeno tiene ningún efecto. Debe añadir una expresión de condición manualmente al eliminar un elemento.En el siguiente ejemplo, se agrega una expresión condicional para garantizar que el elemento eliminado es el elemento que se ha leído. En el siguiente ejemplo,
recordVersiones el atributo del bean anotado con@DynamoDbVersionAttribute.// 1. Read the item and get its current version. Customer item = customerTable.getItem(Key.builder().partitionValue("someId").build()); // `recordVersion` is the bean's attribute that is annotated with `@DynamoDbVersionAttribute`. AttributeValue currentVersion = item.getRecordVersion(); // 2. Create conditional delete with the `currentVersion` value. DeleteItemEnhancedRequest deleteItemRequest = DeleteItemEnhancedRequest.builder() .key(KEY) .conditionExpression(Expression.builder() .expression("recordVersion = :current_version_value") .putExpressionValue(":current_version_value", currentVersion) .build()).build(); customerTable.deleteItem(deleteItemRequest); transactWriteItems-
-
addPutItem: este método tiene el mismo comportamiento queputItem. -
addUpdateItem: este método tiene el mismo comportamiento queupdateItem. -
addDeleteItem: este método tiene el mismo comportamiento quedeleteItem.
-
batchWriteItem-
-
addPutItem: este método tiene el mismo comportamiento queputItem. -
addDeleteItem: este método tiene el mismo comportamiento quedeleteItem.
-
nota
Las tablas globales de DynamoDB usan una conciliación de “el último escritor gana” entre actualizaciones simultáneas. DynamoDB hace todo lo posible para determinar quién realizó la última escritura. Si utiliza tablas globales, esta política de “el último escritor gana” significa que las estrategias de bloqueo pueden no funcionar como se esperaba, ya que todas las réplicas acabarán convergiendo en función de la última escritura determinada por DynamoDB.
Cómo deshabilitar
Para deshabilitar el bloqueo positivo, no utilice la anotación @DynamoDbVersionAttribute.
Implemente contadores con la AtomicCounterExtension
La extensión AtomicCounterExtension incrementa un atributo numérico etiquetado cada vez que se escribe un registro en la base de datos. Se pueden especificar los valores de inicio y de incremento. Si no se especifica ningún valor, el valor inicial se establece en 0 y el valor del atributo se incrementa en 1.
Configuración
Para especificar qué atributo es un contador, etiquete un atributo de tipo Long en el esquema de la tabla.
En el siguiente fragmento se muestra el uso de los valores de inicio e incremento predeterminados para el atributo counter.
@DynamoDbAtomicCounter public Long getCounter() {...}; public void setCounter(Long counter) {...};
El enfoque del esquema de tabla estático se muestra en el siguiente fragmento. La extensión del contador atómico utiliza un valor inicial de 10 e incrementa el valor en 5 cada vez que se escribe el registro.
.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))
Agregue marcas de tiempo con la AutoGeneratedTimestampRecordExtension.
La extensión AutoGeneratedTimestampRecordExtension actualiza automáticamente los atributos de tipo Instant con una marca de tiempo actual cada vez que el elemento se escribe correctamente en la base de datos. Esta extensión no se carga de forma predeterminada.
Configuración
Para especificar qué atributo actualizar con la marca de tiempo actual, etiquete el atributo Instant en el esquema de la tabla.
El atributo lastUpdate es el objetivo del comportamiento de la extensión en el siguiente fragmento. Tenga en cuenta el requisito de que el atributo debe ser de tipo Instant.
@DynamoDbAutoGeneratedTimestampAttribute public Instant getLastUpdate() {...} public void setLastUpdate(Instant lastUpdate) {...}
El enfoque equivalente del esquema de tabla estático se muestra en el siguiente fragmento.
.addAttribute(Instant.class, a -> a.name("lastUpdate") .getter(Customer::getLastUpdate) .setter(Customer::setLastUpdate) // Applying the 'autoGeneratedTimestamp' tag to the attribute. .tags(AutoGeneratedTimestampRecordExtension.AttributeTags.autoGeneratedTimestampAttribute())
Genere un UUID con la AutoGeneratedUuidExtension
La extensión AutoGeneratedUuidExtension genera un UUID (identificador único universal) único para un atributo cuando se escribe un registro nuevo en la base de datos. Utiliza el método UUID.randomUUID()java.lang.String. Esta extensión no se carga de forma predeterminada.
Configuración
El atributo uniqueId es el objetivo del comportamiento de la extensión en el siguiente fragmento.
@AutoGeneratedUuidExtension public String getUniqueId() {...} public void setUniqueId(String uniqueId) {...}
El enfoque equivalente del esquema de tabla estático se muestra en el siguiente fragmento.
.addAttribute(String.class, a -> a.name("uniqueId") .getter(Customer::getUniqueId) .setter(Customer::setUniqueId) // Applying the 'autoGeneratedUuid' tag to the attribute. .tags(AutoGeneratedUuidExtension.AttributeTags.autoGeneratedUuidAttribute())
Si quiere que la extensión rellene el UUID solo para los métodos putItem y no para los métodos updateItem, añade la anotación comportamiento de actualización
@AutoGeneratedUuidExtension @DynamoDbUpdateBehavior(UpdateBehavior.WRITE_IF_NOT_EXISTS) public String getUniqueId() {...} public void setUniqueId(String uniqueId) {...}
Si utiliza el método de esquema de tabla estática, use el siguiente código equivalente.
.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))