Avançado6 min de leitura

Transações do DynamoDB

Uma transação do DynamoDB agrupa várias escritas em uma única operação tudo-ou-nada: ou todas as ações fazem commit, ou nenhuma faz. É como você evita que dois itens relacionados se desencontrem quando uma escrita falha pela metade.

No cenário do log de auditoria, todo evento que você adiciona também deveria incrementar um eventCount por tenant. Se o evento chega mas o contador não — ou vice-versa — o log e a contagem discordam para sempre. Uma transação torna isso impossível.

O DynamoDB suporta transações?

Sim. O DynamoDB suporta transações ACID por meio de TransactWriteItems e TransactGetItems, que agrupam até 100 ações em uma única operação tudo-ou-nada em uma ou mais tabelas. Ou todas as escritas fazem commit, ou nenhuma faz, de modo que itens relacionados não podem se desencontrar. Escritas transacionais custam o dobro da capacidade das escritas normais, e uma condição falha ou conflito cancela toda a requisição.

  • TransactWriteItems agrupa até 100 ações de escrita em uma ou mais tabelas, tudo-ou-nada. O tamanho agregado dos itens não pode exceder 4 MB.
  • As ações são Put, Update, Delete e ConditionCheck. Um ConditionCheck afirma algo sobre um item que você não está escrevendo.
  • Custa o dobro. Uma escrita transacional consome o dobro da capacidade de uma escrita normal — o DynamoDB prepara e depois faz commit.
  • Conflitos e condições falhas cancelam tudo com uma TransactionCanceledException; nada parcial fica para trás.

O problema: duas escritas que precisam concordar

Você quer que cada novo evento de auditoria também incremente a contagem corrente do tenant. Feito como duas chamadas separadas, qualquer falha entre elas corrompe seus dados:

  1. PutItem no novo item EVENT#… — sucesso.
  2. UpdateItem para ADD eventCount 1 — timeout.

Agora o log tem uma linha a mais do que o contador afirma. Repetir o passo 2 às cegas arrisca contagem dupla; não repetir os deixa inconsistentes. Não há recuperação segura porque as duas escritas nunca foram vinculadas.

Vindo do SQL, você envolveria ambas em BEGIN … COMMIT. A resposta do DynamoDB é uma única requisição transacional que carrega ambas as escritas juntas.

Como o TransactWriteItems funciona

Segundo o Guia do Desenvolvedor da AWS, o TransactWriteItems "agrupa até 100 ações de escrita em uma única operação tudo-ou-nada" mirando em até 100 itens distintos, e "o tamanho agregado dos itens na transação não pode exceder 4 MB". As ações se completam de forma atômica — todas têm sucesso ou nenhuma.

Você pode misturar quatro tipos de ação em uma transação:

  • Put — criar ou substituir um item.
  • Update — editar atributos (incluindo ADD para o nosso contador).
  • Delete — remover um item por chave.
  • ConditionCheck — afirmar uma condição sobre um item que você não está, de outra forma, escrevendo (por exemplo, "este tenant ainda está ativo").

Mais duas regras pegam na prática. Primeiro, as transações consomem o dobro da capacidade das escritas não-transacionais equivalentes — o DynamoDB faz uma fase de preparação e uma fase de commit. Segundo, você não pode mirar no mesmo item duas vezes em uma transação, e transações não podem ser executadas contra índices.

"DynamoDB"App"DynamoDB"Appprepare both, checkconditions"TransactWriteItems [Put EVENT,Update counter]""both commit, orTransactionCanceledException"

Um exemplo prático: adicionar + contar, atomicamente

De volta ao log de auditoria. Adicionar um evento para o tenant acme e incrementar seu contador é uma transação com duas ações:

actionitemeffect
PutTENANT#acmeEVENT#2026-06-24T09:14Z#a1write the new audit row
UpdateTENANT#acmeCOUNTERADD eventCount 1

Se a condição de qualquer ação falhar — digamos um ConditionCheck de que o tenant não está suspenso — a requisição inteira é cancelada com uma TransactionCanceledException e nenhuma escrita acontece. O log e o contador nunca podem discordar.

O ConditionExpression em cada ação é a alavanca. Para afirmar que a linha do evento ainda não existe (para que um retry não possa duplicá-la) e que o tenant está ativo, você compõe condições como attribute_not_exists(SK) no Put e status = :active como um ConditionCheck.

Construa e copie essas expressões de condição tipadas no Construtor de Expressões do DynamoDB em vez de montar ExpressionAttributeNames e placeholders :val à mão — o modo de escrita condicional emite exatamente o formato que o TransactWriteItems quer.

Para retries seguros em uma conexão instável, anexe um client token: um TransactWriteItems repetido com o mesmo token dentro de 10 minutos retorna sucesso sem reaplicar as escritas (idempotência).

Faça no DynoTable

O DynoTable usa transações por baixo dos panos para as próprias escritas: quando você prepara várias edições de itens e faz commit delas, ele as envia como TransactWriteItems com expressões de condição de optimistic locking, então o seu lote de edições é tudo-ou-nada — você nunca aplica pela metade uma mudança de múltiplos itens.

Isso significa que você pode editar a linha do evento e o contador no mesmo lote preparado, revisar o diff e fazer commit de ambos atomicamente sem escrever nenhum código de SDK.

Preparando o novo evento de auditoria e a edição do contador do tenant no DynoTable, e então fazendo commit de ambos como uma transação tudo-ou-nada.
Preparando o novo evento de auditoria e a edição do contador do tenant no DynoTable, e então fazendo commit de ambos como uma transação tudo-ou-nada.

Armadilhas e próximos passos

  • Reserve orçamento para o dobro de capacidade. Uma escrita transacional cobra o dobro da WCU de uma escrita comum — tranquilo para o par ocasional crítico para consistência, caro se você envolver cada escrita em uma transação. Use onde a atomicidade realmente importa.
  • Trate a TransactionCanceledException explicitamente. Ela é retornada por uma condição falha ou um conflito com outra transação em andamento nos mesmos itens. As razões de cancelamento te dizem qual ação falhou — inspecione-as, não faça retry às cegas.
  • Os registros de stream não são cientes de transações. As mudanças de uma transação se propagam para o Streams gradualmente e podem se intercalar com outras; os consumidores não podem assumir atomicidade ou ordenação — veja DynamoDB Streams.
  • Não é para contadores de alto throughput. Um único contador quente sob carga transacional concorrente pesada vai dar throttling; para isso, veja atomic counters ou fragmentar o contador.

As transações são a ferramenta para "estas escritas precisam concordar". Uma vez que os eventos estejam chegando de forma consistente, a próxima preocupação é reagir a eles — isso é DynamoDB Streams.

Baixe o DynoTable para preparar edições de múltiplos itens e fazer commit delas como uma única transação contra a sua própria tabela.

Atualizado