

# DynamoDB e bloqueio positivo com número de versão
<a name="DynamoDBMapper.OptimisticLocking"></a>

O *bloqueio positivo * é uma estratégia para garantir que o item no lado do cliente que você está atualizando (ou excluindo) seja o mesmo que o item no Amazon DynamoDB. Se você usar essa estratégia, suas gravações de banco de dados serão protegidas contra substituição pelas gravações de outros e vice-versa.

Com o bloqueio positivo, cada item tem um atributo que serve como um número de versão. Se você recuperar um item de uma tabela, o aplicativo registrará o número da versão desse item. Você poderá atualizar o item somente se o número de versão no lado do servidor não tiver sido alterado. Se há uma incompatibilidade de versão, isso significa que alguém modificou o item antes de você. A tentativa de atualização falha, porque você tem uma versão obsoleta do item. Se isso acontecer, basta tentar novamente ao recuperar o item e tentar atualizá-lo. O bloqueio positivo impede que você substitua acidentalmente as alterações que foram feitas por outros. Também impede que outros substituam acidentalmente suas alterações.

Embora seja possível implementar a própria estratégia de bloqueio positivo, o AWS SDK para Java oferece a anotação `@DynamoDBVersionAttribute`. Na classe de mapeamento da sua tabela, você designa uma propriedade para armazenar o número da versão e a marca usando essa anotação. Quando um objeto é salvo, o item correspondente na tabela do DynamoDB terá um atributo que armazena o número da versão. O `DynamoDBMapper` atribui um número de versão quando você salvar o objeto pela primeira vez e incrementa automaticamente o número da versão sempre que você atualiza o item. Suas solicitações de atualização ou exclusão só serão bem-sucedidas se a versão do objeto no lado do cliente corresponder ao número de versão correspondente do item na tabela do DynamoDB.

 `ConditionalCheckFailedException` será lançada se: 
+  Você usar bloqueio positivo com `@DynamoDBVersionAttribute` e o valor de versão no servidor for diferente do valor no lado do cliente. 
+  Você especificar suas próprias restrições condicionais ao salvar dados usando `DynamoDBMapper` com `DynamoDBSaveExpression` e ocorrer falha nessas restrições. 

**nota**  
As tabelas globais do DynamoDB usam uma reconciliação “último gravador ganha” entre as atualizações simultâneas. Se você usa tabelas globais, a política de último gravador ganha. Portanto, neste caso, a estratégia de bloqueio não funciona como esperado.
As operações de gravação transacional `DynamoDBMapper` não são compatíveis com expressões de condição e anotação `@DynamoDBVersionAttribute` no mesmo objeto. Se um objeto em uma gravação transacional for anotado com `@DynamoDBVersionAttribute` e também tiver uma expressão de condição, a SdkClientException será lançada.

Por exemplo, o código Java a seguir define uma classe `CatalogItem` que tem várias propriedades. A propriedade `Version` está marcada com a anotação `@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;}
}
```

Você pode aplicar a anotação `@DynamoDBVersionAttribute` a tipos anuláveis fornecidos pelas classes wrapper primitivas que fornecem um tipo que permite valor nulo, como `Long` e `Integer`. 

O bloqueio positivo tem o seguinte impacto sobre estes métodos `DynamoDBMapper`:
+ `save`: para um novo item, `DynamoDBMapper` atribui um número de versão inicial 1. Se você recuperar um item, atualizar uma ou mais das suas propriedades e tentar salvar as alterações, a operação de salvamento será bem-sucedida somente se o número de versão no lado do cliente e no lado do servidor corresponderem. A classe `DynamoDBMapper` incrementa o número de versão automaticamente.
+ `delete`: o método `delete` usa um objeto como parâmetro, e `DynamoDBMapper` realiza uma verificação de versão antes de excluir o item. A verificação da versão pode ser desabilitada se `DynamoDBMapperConfig.SaveBehavior.CLOBBER` for especificado na solicitação.

  A implementação interna do bloqueio positivo em `DynamoDBMapper` usa o suporte a atualizações e exclusões condicionais fornecido pelo DynamoDB. 
+ `transactionWrite` —
  + `Put`: para um novo item, `DynamoDBMapper` atribui um número de versão inicial 1. Se você recuperar um item, atualizar uma ou mais das suas propriedades e tentar salvar as alterações, a operação Put será bem-sucedida somente se o número de versão no lado do cliente e no lado do servidor corresponder. A classe `DynamoDBMapper` incrementa o número de versão automaticamente.
  + `Update`: para um novo item, `DynamoDBMapper` atribui um número de versão inicial 1. Se você recuperar um item, atualizar uma ou mais das suas propriedades e tentar salvar as alterações, a operação Update será bem-sucedida somente se o número de versão no lado do cliente e no lado do servidor corresponder. A classe `DynamoDBMapper` incrementa o número de versão automaticamente.
  + `Delete`: o `DynamoDBMapper` realiza uma verificação de versão antes de excluir o item. A operação Delete só será bem-sucedida se o número de versão no lado do cliente e no lado do servidor corresponder.
  + `ConditionCheck`: a anotação `@DynamoDBVersionAttribute` não é compatível com operações `ConditionCheck`. Uma SdkClientException será lançada quando um item `ConditionCheck` for anotado com `@DynamoDBVersionAttribute`. 

## Desabilitar o bloqueio positivo
<a name="DynamoDBMapper.OptimisticLocking.Disabling"></a>

Para desabilitar o bloqueio positivo, você pode alterar o valor de enumeração `DynamoDBMapperConfig.SaveBehavior` de `UPDATE` para `CLOBBER`. Você pode fazer isso criando uma instância de `DynamoDBMapperConfig` que ignora a verificação de versão e usando essa instância para todas as suas solicitações. Para obter informações sobre `DynamoDBMapperConfig.SaveBehavior` e outros parâmetros `DynamoDBMapper` opcionais, consulte [Definições de configuração opcionais para DynamoDBMapper](DynamoDBMapper.OptionalConfig.md). 

Você também pode definir um comportamento de bloqueio somente para uma operação específica. Por exemplo, o seguinte trecho de código Java usa `DynamoDBMapper` para salvar um item de catálogo. Ele especifica `DynamoDBMapperConfig.SaveBehavior` adicionando o parâmetro `DynamoDBMapperConfig` opcional ao método `save`. 

**nota**  
O método transactionWrite não oferece suporte à configuração DynamoDBMapperConfig.SaveBehavior. A desabilitação do bloqueio positivo para transactionWrite é incompatível.

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