Bloqueo positivo con el número de versión - Amazon DynamoDB

Bloqueo positivo con el número de versión

El bloqueo optimista es una estrategia para asegurarse de que el elemento del lado del cliente que se va a actualizar (o eliminar) sea el mismo que figura en Amazon DynamoDB. Si utiliza esta estrategia, las escrituras en su base de datos se protegen contra posibles sobrescrituras de otros y viceversa.

Con el bloqueo optimista, cada elemento tiene un atributo que actúa como número de versión. Si recupera un elemento de una tabla, la aplicación registra el número de versión de ese elemento. Puede actualizar el elemento, pero solo si el número de versión del lado del servidor no ha cambiado. Si no hay una coincidencia de versión, significa que alguien más ha modificado el elemento antes que usted. El intento de actualización falla porque tiene una versión obsoleta del elemento. Si esto ocurre, intente recuperar el elemento y actualizarlo. El bloqueo optimista impide que sobrescriba accidentalmente los cambios realizados por otras personas. También impide que otras personas sobrescriban accidentalmente sus cambios.

Si bien puede implementar su propia estrategia de bloqueo positivo, AWS SDK for Java proporciona la anotación @DynamoDBVersionAttribute. En la clase de mapeo de la tabla, debe designar una propiedad en la que se almacenará el número de versión y marcarla con esta anotación. Al guardar un objeto, el elemento correspondiente de la tabla de DynamoDB tendrá un atributo en el que se almacenará el número de versión. DynamoDBMapper asigna un número de versión la primera vez que se guarda el objeto y aumenta automáticamente este número de versión cada vez que se actualiza el elemento. Las solicitudes de actualización o eliminación solamente se llevan a cabo si la versión del objeto en el lado del cliente coincide con el número de versión del elemento correspondiente en la tabla de DynamoDB.

ConditionalCheckFailedException se lanza si:

  • Utiliza el bloqueo optimista con @DynamoDBVersionAttribute y el valor de versión en el servidor es distinto del valor en el lado del cliente.

  • Especifique sus propias limitaciones condicionales al guardar los datos utilizando DynamoDBMapper con DynamoDBSaveExpression y estas limitaciones han fallado.

nota
  • Las tablas globales de DynamoDB usan una reconciliación del tipo "prevalece el último escritor" entre las actualizaciones simultáneas. Si usa tablas globales, prevalecerá la política del último escritor. Por tanto, en este caso, la estrategia de bloqueo no funciona según lo previsto.

  • Las operaciones de escritura transaccional DynamoDBMapper no admiten expresiones de anotación y condición @DynamoDBVersionAttribute en el mismo objeto. Si un objeto en una escritura transacciones se anota con @DynamoDBVersionAttribute y también tiene una expresión de condición, se producirá una SdkClientException.

Por ejemplo, en el siguiente código Java se define una clase CatalogItem que tiene varias propiedades. La propiedad Version está etiquetada con la anotación @DynamoDBVersionAttribute.

ejemplo
@DynamoDBTable(tableName="ProductCatalog") public class CatalogItem { private Integer id; private String title; private String ISBN; private Set<String> bookAuthors; private String someProp; private Long version; @DynamoDBHashKey(attributeName="Id") public Integer getId() { return id; } public void setId(Integer Id) { this.id = Id; } @DynamoDBAttribute(attributeName="Title") public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } @DynamoDBAttribute(attributeName="ISBN") public String getISBN() { return ISBN; } public void setISBN(String ISBN) { this.ISBN = ISBN;} @DynamoDBAttribute(attributeName = "Authors") public Set<String> getBookAuthors() { return bookAuthors; } public void setBookAuthors(Set<String> bookAuthors) { this.bookAuthors = bookAuthors; } @DynamoDBIgnore public String getSomeProp() { return someProp;} public void setSomeProp(String someProp) {this.someProp = someProp;} @DynamoDBVersionAttribute public Long getVersion() { return version; } public void setVersion(Long version) { this.version = version;} }

Puede aplicar la anotación @DynamoDBVersionAttribute a los tipos que admiten valores null; estos están disponibles en las clases encapsuladoras primitivas que proporcionan un tipo que admite valores null, tales como Long e Integer.

El bloqueo optimista afecta a los siguientes métodos de DynamoDBMapper como se indica a continuación:

  • save: para un elemento nuevo, DynamoDBMapper asigna un número de versión inicial de 1. Si recupera un elemento, actualiza una o varias de sus propiedades e intenta guardar los cambios, la operación de almacenamiento 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. DynamoDBMapper incrementa el número de versión automáticamente.

  • delete: el método delete toma un objeto como parámetro y DynamoDBMapper lleva a cabo una comprobación de versión antes de eliminar el elemento. La comprobación de versión se puede deshabilitar si se especifica DynamoDBMapperConfig.SaveBehavior.CLOBBER en la solicitud.

    La implementación interna del bloqueo optimista en DynamoDBMapper utiliza la compatibilidad con las acciones de actualización condicional y eliminación condicional que DynamoDB proporciona.

  • transactionWrite

    • Put: para un elemento nuevo, DynamoDBMapper asigna un número de versión inicial de 1. Si recupera un elemento, actualiza una o varias de sus propiedades e intenta guardar los cambios, la operación put 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. DynamoDBMapper incrementa el número de versión automáticamente.

    • Update: para un elemento nuevo, DynamoDBMapper asigna un número de versión inicial de 1. Si recupera un elemento, actualiza una o varias de sus propiedades e intenta guardar los cambios, la operación update 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. DynamoDBMapper incrementa el número de versión automáticamente.

    • Delete: DynamoDBMapper realiza una comprobación de versión antes de eliminar el elemento. La operación de eliminación solo se realiza correctamente si coincide el número de versión en el lado del cliente y en el lado del servidor.

    • ConditionCheck: la anotación @DynamoDBVersionAttribute no es compatible con ConditionCheck. Se producirá una excepción SdkClientException cuando un elemento ConditionCheck se anote con @DynamoDBVersionAttribute.

Deshabilitación del bloqueo positivo

Para deshabilitar el bloqueo optimista, puede cambiar el valor de enumeración DynamoDBMapperConfig.SaveBehavior de UPDATE a CLOBBER. Para ello, puede crear una instancia de DynamoDBMapperConfig que omita la comprobación de versión y usar esta instancia en todas las solicitudes. Para obtener información acerca de DynamoDBMapperConfig.SaveBehavior y otros parámetros opcionales de DynamoDBMapper, consulte Ajustes de configuración opcionales para DynamoDBMapper .

También puede establecer el comportamiento de bloqueo para una operación específica. Por ejemplo, en el siguiente fragmento de código Java se usa DynamoDBMapper para guardar un elemento de catálogo. Se agrega el parámetro opcional DynamoDBMapperConfig.SaveBehavior al método DynamoDBMapperConfig para especificar save.

nota

El método transactionWrite method no admite la configuración DynamoDBMapperConfig.SaveBehavior. No se admite la deshabilitación del bloqueo optimista para transactionWrite.

ejemplo
DynamoDBMapper mapper = new DynamoDBMapper(client); // Load a catalog item. CatalogItem item = mapper.load(CatalogItem.class, 101); item.setTitle("This is a new title for the item"); ... // Save the item. mapper.save(item, new DynamoDBMapperConfig( DynamoDBMapperConfig.SaveBehavior.CLOBBER));