

# Bloqueio positivo com número de versão
<a name="BestPractices_OptimisticLocking"></a>

O bloqueio positivo é uma estratégia que detecta conflitos no momento da gravação, em vez de evitá-los. Cada item inclui um atributo de versão que aumenta a cada atualização. Ao atualizar um item, é necessário incluir uma [expressão de condição](Expressions.ConditionExpressions.md) que verifica se o número da versão corresponde ao valor que a aplicação leu pela última vez. Se outro processo modificou o item nesse meio tempo, a condição falhará e o DynamoDB exibirá uma `ConditionalCheckFailedException`.

## Quando usar o bloqueio positivo
<a name="BestPractices_OptimisticLocking_WhenToUse"></a>

O bloqueio positivo é uma boa opção quando:
+ Vários usuários ou processos podem tentar atualizar o mesmo item, mas os conflitos são infrequentes.
+ O custo de tentar novamente uma gravação é baixo para a aplicação.
+ Você deseja evitar os custos indiretos e a complexidade do gerenciamento de bloqueios distribuídos.

Os exemplos comuns incluem atualizações de inventário de comércio eletrônico, plataformas de edição colaborativa e registros de transações financeiras.

## Desvantagens
<a name="BestPractices_OptimisticLocking_Tradeoffs"></a>

**Custos indiretos de novas tentativas em alta contenção**  
Em ambientes de alta simultaneidade, a probabilidade de conflitos aumenta, podendo gerar mais tentativas e custos de gravação.

**Complexidade de implementação**  
Adicionar controle de versão aos itens e lidar com verificações condicionais pode aumentar complexidade da lógica da aplicação. O AWS SDK para Java v2 Enhanced Client oferece suporte integrado por meio da anotação [https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/ddb-en-client-extensions.html#ddb-en-client-extensions-VRE](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/ddb-en-client-extensions.html#ddb-en-client-extensions-VRE), que gerencia automaticamente os números de versão para você.

## Padrão de design
<a name="BestPractices_OptimisticLocking_PatternDesign"></a>

Inclua um atributo de versão em cada item. Aqui está um design de esquema simples:
+ Chave de partição: um identificador exclusivo para cada item (por exemplo, `ItemId`).
+ Atributos:
  + `ItemId`: o identificador exclusivo do item.
  + `Version`: um número inteiro que representa o número da versão do item.
  + `QuantityLeft`: o estoque restante do item.

Quando um item é criado pela primeira vez, o atributo `Version` é definido como 1. Com cada atualização, o número da versão é incrementado em 1.


| ItemID (chave de partição) | Versão | QuantityLeft | 
| --- | --- | --- | 
| Bananas | 1 | 10 | 
| Maçãs | 1 | 5 | 
| Laranjas | 1 | 7 | 

## Implementação
<a name="BestPractices_OptimisticLocking_Implementation"></a>

Para implementar o bloqueio positivo, siga estas etapas:

1. Leia a versão atual do item.

   ```
   def get_item(item_id):
       response = table.get_item(Key={'ItemID': item_id})
       return response['Item']
   
   item = get_item('Bananas')
   current_version = item['Version']
   ```

1. Atualize o item usando uma expressão de condição que verifica o número da versão.

   ```
   def update_item(item_id, qty_bought, current_version):
       try:
           response = table.update_item(
               Key={'ItemID': item_id},
               UpdateExpression="SET QuantityLeft = QuantityLeft - :qty, Version = :new_v",
               ConditionExpression="Version = :expected_v",
               ExpressionAttributeValues={
                   ':qty': qty_bought,
                   ':new_v': current_version + 1,
                   ':expected_v': current_version
               },
               ReturnValues="UPDATED_NEW"
           )
           return response
       except ClientError as e:
           if e.response['Error']['Code'] == 'ConditionalCheckFailedException':
               print("Version conflict: another process updated this item.")
           raise
   ```

1. Resolva os conflitos tentando novamente com uma nova leitura.

   Como cada nova tentativa requer uma leitura adicional, limite o número total de novas tentativas.

   ```
   def update_with_retry(item_id, qty_bought, max_retries=3):
       for attempt in range(max_retries):
           item = get_item(item_id)
           try:
               return update_item(item_id, qty_bought, item['Version'])
           except ClientError as e:
               if e.response['Error']['Code'] != 'ConditionalCheckFailedException':
                   raise
               print(f"Retry {attempt + 1}/{max_retries}")
       raise Exception("Update failed after maximum retries.")
   ```

Em aplicações Java, o AWS SDK para Java v2 Enhanced Client oferece suporte integrado a bloqueio positivo por meio da anotação[https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/ddb-en-client-extensions.html#ddb-en-client-extensions-VRE](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/ddb-en-client-extensions.html#ddb-en-client-extensions-VRE), que gerencia automaticamente os números de versão para você.

Para ter mais informações sobre expressões de condição, consulte [Exemplo de expressão de condição do DynamoDB na CLI](Expressions.ConditionExpressions.md).