

# Bloqueio negativo com transações do DynamoDB
<a name="BestPractices_PessimisticLocking"></a>

As transações do [DynamoDB](transactions.md) oferecem uma abordagem de tudo ou nada para operações agrupadas. Quando você usa `TransactWriteItems`, o DynamoDB monitora todos os itens na transação. Se algum item for modificado por outra operação durante a transação, toda a transação será cancelada e o DynamoDB exibirá uma `TransactionCanceledException`. Esse comportamento oferece uma forma de controle de simultaneidade negativo porque modificações simultâneas conflitantes são evitadas em vez de detectadas assim que ocorrem.

## Quando usar transações para bloqueio
<a name="BestPractices_PessimisticLocking_WhenToUse"></a>

As transações são uma boa opção quando:
+ É necessário atualizar vários itens atomicamente, dentro da mesma tabela ou entre tabelas.
+ A lógica de negócios exige uma semântica de tudo ou nada: ou todas as alterações têm êxito ou nenhuma é aplicada.

Exemplos comuns incluem transferir fundos entre contas, fazer pedidos que atualizem o inventário e as tabelas de pedidos e trocar itens entre jogadores em um jogo.

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

**Custo de gravação mais alto**  
Para itens de até 1 KB, as transações consomem 2 WCUs por item (uma para preparar e outra para confirmar), em comparação com 1 WCU para uma gravação padrão.

**Limite de itens**  
Uma única transação pode incluir até cem ações em uma ou mais tabelas.

**Sensibilidade a conflitos**  
Se algum item for modificado por outra operação, toda a transação falhará. Em cenários de alta contenção, isso pode levar a cancelamentos frequentes.

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

O exemplo a seguir usa `TransactWriteItems` para transferir inventário entre dois itens atomicamente. Se outro processo modificar qualquer item durante a transação, toda a operação será revertida.

```
import boto3

client = boto3.client('dynamodb')

def transfer_inventory(source_id, target_id, quantity):
    try:
        client.transact_write_items(
            TransactItems=[
                {
                    'Update': {
                        'TableName': 'Inventory',
                        'Key': {'ItemID': {'S': source_id}},
                        'UpdateExpression': 'SET QuantityLeft = QuantityLeft - :qty',
                        'ConditionExpression': 'QuantityLeft >= :qty',
                        'ExpressionAttributeValues': {
                            ':qty': {'N': str(quantity)}
                        }
                    }
                },
                {
                    'Update': {
                        'TableName': 'Inventory',
                        'Key': {'ItemID': {'S': target_id}},
                        'UpdateExpression': 'SET QuantityLeft = QuantityLeft + :qty',
                        'ExpressionAttributeValues': {
                            ':qty': {'N': str(quantity)}
                        }
                    }
                }
            ]
        )
        return True
    except client.exceptions.TransactionCanceledException as e:
        print(f"Transaction canceled: {e}")
        return False
```

Neste exemplo, a expressão de condição verifica se existe inventário suficiente, mas nenhum atributo de versão é necessário. O DynamoDB cancelará automaticamente a transação se algum item da transação for modificado por outra operação entre as fases de preparação e confirmação. É isso que oferece o controle de simultaneidade negativo: modificações simultâneas conflitantes são evitadas pela própria transação.

**nota**  
É possível associar transações com bloqueio positivo adicionando verificações de versão como expressões de condição adicionais. Isso oferece um nível extra de proteção, mas não é necessário para que a transação detecte conflitos.

Para obter mais informações, consulte [Gerenciar fluxos de trabalho complexos com transações do DynamoDB](transactions.md).