

# DynamoDB y bloqueo positivo con el número de versión
<a name="DynamoDBMapper.OptimisticLocking"></a>

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 para 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`.

**Example**  

```
@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
<a name="DynamoDBMapper.OptimisticLocking.Disabling"></a>

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](DynamoDBMapper.OptionalConfig.md). 

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.

**Example**  

```
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));
```