MongoDB: Processamento de transações

Última atualização: 2026-08-26

As transações garantem a atomicidade das operações envolvendo vários documentos — o domínio desse conceito permite o desenvolvimento de sistemas financeiros e de pedidos confiáveis.

1. O que você vai aprender


100%
sequenceDiagram
    participant App as Applications
    participant DB as MongoDB<br/>Dungeon Collection
    participant Log as Log

    App->>DB: startTransaction()
    activate DB
    DB-->>App: session

    App->>DB: Deduct $100
    DB-->>App: OK
    App->>DB: Add $100
    DB-->>App: OK
    App->>DB: Create a Transaction Log
    DB-->>App: OK

    alt All successful
        App->>DB: commitTransaction()
        DB-->>App: ✅ Committed
        DB->>Log: Persistence
    else Any failure
        App->>DB: abortTransaction()
        DB-->>App: ❌ Rollback
        Note over DB: All changes have been reversed<br/>Data is rolled back to the state before the transaction
    end

    deactivate DB

2. Por que as transações são necessárias?

Explicação do conceito: Uma transação é uma unidade lógica de operações de banco de dados que garante que todas as operações nela contidas sejam totalmente bem-sucedidas ou totalmente revertidas. Ao gravar em vários documentos ou coleções (como em transferências de fundos ou na realização de pedidos), a consistência dos dados não pode ser garantida sem transações — o sucesso parcial e a falha parcial resultariam em dados inconsistentes.

Como funciona: O MongoDB 4.0 e versões posteriores oferecem suporte a transações ACID com múltiplos documentos, implementadas por meio do isolamento de instantâneo com base no mecanismo WiredTiger. Quando uma transação é iniciada, um instantâneo é criado, e todas as operações de leitura e gravação são realizadas em relação a esse instantâneo; no momento do commit, as alterações são aplicadas de forma atômica aos arquivos de dados e, no momento do rollback, todas as alterações são descartadas. Nos bastidores, as transações dependem do oplog do conjunto de réplicas para garantir a persistência e a replicação.

Uma explicação detalhada dos princípios ACID:

Recurso Significado Implementação no MongoDB Princípio
Atomicidade As transações são totalmente bem-sucedidas ou totalmente malsucedidas commit / abort O WiredTiger garante isso por meio do log de reversão: gravações atômicas durante o commit e recuperação usando o log de reversão durante a reversão
Consistência As restrições de integridade dos dados permanecem inalteradas Validação do esquema + restrições de transação Todas as restrições são verificadas antes do commit de uma transação; se alguma for violada, a transação é rejeitada
Isolamento As transações simultâneas não interferem umas nas outras Isolamento por instantâneo É criado um instantâneo dos dados no início de uma transação; todas as leituras e gravações se baseiam nesse instantâneo ao longo da transação, e a transação não é afetada por outras transações
Durabilidade Armazenado permanentemente após a confirmação da transação Diário + oplog do conjunto de réplicas As gravações são primeiro registradas no diário (WAL) e, em seguida, replicadas para a maioria dos nós do conjunto de réplicas

Mecanismo MVCC: O MongoDB implementa o isolamento por snapshot por meio do Controle de Concorrência Multiversão (MVCC). Cada documento mantém várias versões históricas; as transações leem os dados da versão correspondente ao seu carimbo de data/hora de início, e as operações de gravação criam novas versões sem sobrescrever as antigas. A nova versão só se torna visível para outras transações após a confirmação.

100%
graph TB
    subgraph "MVCC Multiple Versions"
        D1["Document v1<br/>balance: 1000"]
        D2["Document v2<br/>balance: 900<br/>(Transaction A Edit)"]
        D3["Document v3<br/>balance: 1100<br/>(Transaction B Edit)"]
    end

    subgraph "Transaction Snapshot Read"
        T1["TransactionsA (t1)<br/>Read v1"] --> R1["balance: 1000"]
        T2["TransactionsB (t2)<br/>Read v1"] --> R2["balance: 1000"]
    end

    D1 --> D2
    D1 --> D3

    style D2 fill:#cce5ff
    style D3 fill:#d4edda

Casos de uso:

JAVASCRIPT
// ❌ Counterexample: Transfer without a transaction
async function transfer(fromUserId, toUserId, amount) {
  await User.updateOne({ _id: fromUserId }, { $inc: { balance: -amount } });
  // System Crash!
  await User.updateOne({ _id: toUserId }, { $inc: { balance: amount } });
  // The user's balance was deducted, but the recipient did not receive the payment
}

3. Noções básicas sobre transações

Explicação do conceito: As transações no MongoDB são gerenciadas por meio de objetos Session — startSession() cria uma sessão, startTransaction() inicia uma transação, commitTransaction() confirma e abortTransaction() reverte. Todas as operações dentro de uma transação devem ser passadas como parâmetros de { session }.

Como funciona: O ciclo de vida completo de uma transação é o seguinte: iniciar sessão → iniciar transação → executar operações (com parâmetros de sessão) → confirmar/reverter → encerrar sessão. Ao confirmar, o WiredTiger grava de forma atômica todas as alterações no diário; ao reverter, ele reverte todas as alterações usando o log de reversão. O tempo limite padrão da transação é de 60 segundos; as transações são revertidas automaticamente se ultrapassarem esse tempo limite.

Ciclo de vida da transação:

100%
stateDiagram-v2
    [*] --> StartSession: startSession()
    StartSession --> Active: startTransaction()
    Active --> Active: Perform an action (with session)
    Active --> Committed: commitTransaction()
    Active --> Aborted: abortTransaction()
    Committed --> [*]: endSession()
    Aborted --> [*]: endSession()

    note right of Active: Default 60s automatic rollback on timeout
    note right of Committed: Persist changes to journal

Regras gramaticais:

Etapa Método Descrição
1 startSession() Criar uma sessão
2 startTransaction() Iniciar transação
3 Operação + {session} Todas as operações de leitura e gravação devem passar pela sessão
4a commitTransaction() Tudo correu bem → Enviar
4b abortTransaction() Qualquer falha → Revertida
5 endSession() Liberar recursos da sessão
JAVASCRIPT
// === MongoDB 4.0+ Multi-document transactions ===
const session = db.getMongo().startSession();

session.startTransaction();
try {
  // 1. Deduct
  db.users.updateOne(
    { _id: fromUserId },
    { $inc: { balance: -amount } },
    { session }
  );

  // 2. Add
  db.users.updateOne(
    { _id: toUserId },
    { $inc: { balance: amount } },
    { session }
  );

  // 3. Commit Transaction
  await session.commitTransaction();
} catch (err) {
  // 4. Rollback
  await session.abortTransaction();
  throw err;
} finally {
  session.endSession();
}

Análise dos pontos-chave:

  1. A operação para anular a transmissão de { session } não faz parte de uma transação e não é protegida por ela.
  2. commitTransaction e abortTransaction são operações idempotentes; chamá-las repetidamente não resultará em erro.
  3. As transações são automaticamente revertidas ao atingir o tempo limite; a camada de aplicação deve definir um tempo limite razoável e implementar uma lógica de repetição de tentativas.

4. Propriedades do ACID

Visão geral do conceito: ACID refere-se às quatro garantias fundamentais das transações em bancos de dados — Atomicidade, Consistência, Isolamento e Durabilidade. Compreender como o ACID é implementado no MongoDB é a base para projetar um sistema transacional confiável.

Explicação detalhada dos níveis de isolamento: O MongoDB oferece suporte a três níveis de isolamento de leitura, que são controlados por meio de readConcern:

Nível de isolamento readConcern Comportamento Caso de uso
Ler dados não enviados local Ler os dados locais mais recentes (pode ocorrer reversão) Padrão, prioridade no desempenho
Leitura confirmada majority Leitura de dados que foram confirmados pela maioria Requisito de consistência forte
Isolamento por instantâneo snapshot Instantâneo com consistência de leitura dentro da transação Padrão dentro da transação
100%
sequenceDiagram
    participant T1 as Transactions1
    participant T2 as Transactions2
    participant DB as MongoDB

    Note over DB: Initial balance=1000

    T1->>DB: startTransaction(readConcern: snapshot)
    T1->>DB: Read balance → 1000

    T2->>DB: startTransaction()
    T2->>DB: balance -100 → Write 900
    T2->>DB: commitTransaction()

    T1->>DB: Read balance → 1000 (Snapshot isolation, can't see T2 changes)

    Note over T1: Snapshots ensure intra-transaction consistency

    T1->>DB: commitTransaction()
    Note over DB: Conflict detection → If T1 also modifies balance, an error will be reported
Recurso Significado Implementação no MongoDB
Atomicidade A transação é totalmente bem-sucedida ou totalmente malsucedida commit / abort
Consistência Restrições de integridade de dados Validação de esquema + transações
Isolamento As transações simultâneas não interferem umas nas outras Isolamento por instantâneo
Durabilidade Armazenado permanentemente após a confirmação da transação Diário + conjunto de réplicas

5. readConcern / writeConcern / readPreference

Explicação do conceito: Essas três configurações formam a “trindade” do controle de consistência de transações do MongoDB, regendo, respectivamente, a consistência de leitura, a durabilidade de gravação e as políticas de roteamento de leitura. Elas determinam o equilíbrio entre consistência e desempenho nas transações.

Como funciona:

(1) Preocupação com a redação

Princípio: Após uma operação de gravação ser registrada no Primário, ela deve aguardar um número especificado de confirmações do Secundário de que os dados foram replicados antes de retornar um resultado de sucesso.

Parâmetro Valor Comportamento Consistência Desempenho
w 1 Apenas confirmação primária Baixa Mais rápida
w maioria confirmado pela maioria dos nós alto lento
j true Gravar no diário do disco Mais rápido Mais lento
wtimeout ms Tempo limite de espera Erro de tempo limite
JAVASCRIPT
session.startTransaction({
  writeConcern: {
    w: 'majority',         // Confirmed by a majority of nodes
    j: true,               // Write to disk journal
    wtimeout: 5000         // 5 Timeout in seconds
  }
});

(2) Preocupação com a leitura

Princípio: Determina quais versões dos dados uma operação de leitura pode acessar — se a versão local mais recente (que pode não ter sido confirmada) ou a versão com o maior número de confirmações (que já foi confirmada).

Nível Descrição Cenários aplicáveis
local Lê os dados locais mais recentes (padrão) Orientado para o desempenho; permite a leitura de dados não confirmados
majority Ler dados que já foram amplamente confirmados Consistência forte
snapshot Isolamento por instantâneo (apenas dentro de uma transação) Padrão para transações; evita leituras fantasmas
JAVASCRIPT
session.startTransaction({
  readConcern: {
    level: 'majority'      // Read Submitted Data
  },
  writeConcern: { w: 'majority' }
});

(3) Ler preferências

Princípio: Determina se as operações de leitura são encaminhadas para o nó primário ou secundário, implementando assim a separação entre leitura e gravação.

Padrão Comportamento Cenários aplicáveis
primary Nó primário somente leitura Transações fortemente consistentes
primaryPreferred Priorizar o primário; se indisponível, recorrer ao secundário Cenários gerais
secondary Nó secundário somente para leitura Relatórios/análise, alívio da carga do nó primário
secondaryPreferred Priorizar a leitura; recorrer ao primário caso este não esteja disponível Predominância de leitura, poucas gravações
nearest Menor latência de rede Cluster geograficamente distribuído
JAVASCRIPT
session.startTransaction({
  readPreference: 'primary'             // Read-Only Primary Node
});

session.startTransaction({
  readPreference: 'secondary'           // Read from a child node
});

session.startTransaction({
  readPreference: 'secondaryPreferred'  // Priority Node
});

Conjuntos de três peças recomendados:

Cenário writeConcern readConcern readPreference
Transações financeiras maioria + j:true instantâneo primário
Transações gerais maioria maioria principal
Análise do relatório local secundário
Desenvolvimento e Testes w:1 local primaryPreferred

6. Encapsulamento de transações no Mongoose

Explicação do conceito: O Mongoose oferece uma API de transações mais elegante — os parâmetros startSession() e session. No entanto, o código padrão do tipo “try-catch-commit-abort”, usado para gerenciar transações manualmente, é prolixo; encapsulá-lo na função utilitária withTransaction pode simplificar significativamente o código da lógica de negócios.

Como funciona: O wrapper withTransaction do Mongoose automatiza o gerenciamento do ciclo de vida da sessão (início → confirmação/cancelamento → fim), permitindo que as funções de negócios se concentrem exclusivamente na lógica principal. O Mongoose também oferece suporte à passagem de parâmetros { session } para operações de modelo (findById, create, updateOne), possibilitando a integração perfeita de operações CRUD dentro de transações.

Comparação de padrões de encapsulamento de transações:

Padrão Tamanho do código Tratamento de erros Suporte à repetição de tentativas Casos de uso
Try-catch manual Múltiplo Manual Nenhum Cenários simples
Encapsulamento com transação Poucos Automático Pode ser adicionado Recomendado para produção
mongoose.connection.transaction Mínimo Automático Integrado Mongoose 6+
JAVASCRIPT
// === mongoose Transaction Encapsulation ===
async function withTransaction(callback) {
  const session = await mongoose.startSession();
  session.startTransaction();
  try {
    const result = await callback(session);
    await session.commitTransaction();
    return result;
  } catch (err) {
    await session.abortTransaction();
    throw err;
  } finally {
    session.endSession();
  }
}

// === Usage: Transfer ===
async function transfer(fromUserId, toUserId, amount) {
  return withTransaction(async (session) => {
    const fromUser = await User.findById(fromUserId).session(session);
    if (fromUser.balance < amount) {
      throw new Error('Insufficient balance');
    }

    await User.updateOne(
      { _id: fromUserId },
      { $inc: { balance: -amount } },
      { session }
    );

    await User.updateOne(
      { _id: toUserId },
      { $inc: { balance: amount } },
      { session }
    );

    await TransactionLog.create([{
      fromUserId,
      toUserId,
      amount,
      createdAt: new Date()
    }], { session });

    return { success: true };
  });
}

▶ Exemplo 2: Encapsulamento da repetição de transações no Mongoose

JAVASCRIPT
// Alice's ShopHub Financial System: Transaction encountered WriteConflict automatic retry
async function withRetryTransaction(callback, maxRetries = 3) {
  let lastError;
  for (let i = 0; i < maxRetries; i++) {
    const session = await mongoose.startSession();
    session.startTransaction({
      readConcern: { level: 'snapshot' },
      writeConcern: { w: 'majority' }
    });
    try {
      const result = await callback(session);
      await session.commitTransaction();
      return result;
    } catch (err) {
      await session.abortTransaction();
      lastError = err;
      if (err.errorLabels && err.errorLabels.includes('TransientTransactionError')) {
        console.log(`Retry ${i + 1}/${maxRetries} due to WriteConflict`);
        continue;
      }
      throw err;
    } finally {
      session.endSession();
    }
  }
  throw lastError;
}

// Usage
await withRetryTransaction(async (session) => {
  await User.updateOne({ _id: fromId }, { $inc: { balance: -100 } }, { session });
  await User.updateOne({ _id: toId }, { $inc: { balance: 100 } }, { session });
});

7. Limites de transações

Explicação do conceito: As transações do MongoDB têm limites de uso bem definidos — elas devem ser realizadas dentro de um conjunto de réplicas, estão sujeitas a limites de tamanho e não suportam determinadas operações. Compreender essas limitações é fundamental para evitar incidentes em produção.

Explicação detalhada das restrições:

Restrição Descrição Motivo Estratégia de mitigação
São necessários conjuntos de réplicas O MongoDB autônomo não oferece suporte a transações As transações dependem do oplog para persistência É permitido um conjunto de réplicas de nó único em ambientes de desenvolvimento
Documento de 16 MB Total de todas as operações dentro de uma transação Limite de um único documento do WiredTiger Divisão de transações grandes em transações menores
Tempo limite padrão de 60 segundos maxTransactionLockRequestTimeoutMillis Evitar que transações demoradas mantenham bloqueios Ajustar o parâmetro de tempo limite
Não é possível realizar operações em uma coleção com limite Restrições parciais Não é possível reverter transações em coleções com limite Evite realizar operações em coleções com limite dentro de transações
Não é possível criar conjuntos dentro de uma transação Restrição parcial (flexibilizada na versão 4.4+) Conflito entre DDL e transações Crie os conjuntos antes da transação
Conflitos de gravação Modificações simultâneas no mesmo documento Mecanismo de bloqueio otimista Nova tentativa automática em caso de TransientTransactionError
Espera por bloqueio Transações longas bloqueiam outras operações Bloqueio de intenção de gravação Reduza a duração das transações para evitar operações demoradas

Impacto no desempenho das transações:

Operação Não transacional Dentro de uma transação Motivo da sobrecarga
Gravação em um único documento Teste de desempenho +30–50% Manutenção de instantâneos + gerenciamento de bloqueios
Gravação em vários documentos N operações independentes de E/S 1 confirmação A fusão de transações em uma única operação de E/S pode, na verdade, ser mais rápida
Leitura Linha de base +10–20% Sobrecarga adicional para leituras de instantâneos
Enviar 5–50 ms fsync do diário + gravação no oplog

Melhores práticas para transações:

Exercício Descrição
Mantenha as transações o mais curtas possível Evite transações longas que mantenham bloqueios; mantenha-as abaixo de 100 ms
Evite cálculos dentro de transações Realize cálculos complexos fora das transações; limite as transações apenas a operações de leitura e gravação
Repetição de tentativas em casos de conflitos de gravação O MongoDB 4.0+ oferece o errorLabels para identificar erros que podem ser repetidos
Priorizar operações atômicas em um único documento updateOne + $inc é atômico por si só; não é necessária nenhuma transação

8. Consistência causal

Explicação do conceito: A consistência causal é um modelo de consistência mais leve do que a consistência forte — ela não garante que todas as operações sejam ordenadas globalmente, mas garante que as operações com relações causais sejam executadas na ordem correta. Por exemplo, “ler o saldo primeiro e, em seguida, deduzir o valor” — a operação de dedução deve se basear no saldo lido mais recentemente; essa é uma dependência causal.

Como funciona: O MongoDB alcança a consistência causal por meio de operationTime e clusterTime. Cada operação dentro de uma sessão herda o logicalTime da operação anterior, e o servidor garante que as operações subsequentes vejam os resultados das operações anteriores. Para habilitar a consistência causal, é necessário readConcern: majority + writeConcern: majority.

Consistência causal versus outros modelos de consistência:

Modelo Garantia Desempenho Aplicabilidade
Consistência forte (linearizável) Ordenação global Mais lenta Núcleo financeiro
Consistência causal Ordem causal Relativamente rápido Operações em várias etapas
Consistência eventual Não ordenado Mais rápido Registros, notificações
Ler minhas postagens Minhas postagens estão visíveis Rápido Experiência do usuário
100%
sequenceDiagram
    participant A as Alice
    participant P as Primary
    participant S as Secondary

    A->>P: Read Balance (readConcern: majority)
    P-->>A: balance=1000, clusterTime=t1

    A->>P: Deduct $100 (writeConcern: majority)
    Note over A,P: Carry afterClusterTime=t1
    P->>S: Copy oplog
    S-->>P: Confirm
    P-->>A: OK, clusterTime=t2

    A->>P: View Transaction History (readConcern: majority)
    Note over A,P: Carry afterClusterTime=t2
    P-->>A: Includes records of payments that have just been deducted ✅

    Note over A,P: Consistency of Cause and Effect:If you read it, you're sure to recognize your own previous writing.
JAVASCRIPT
// === Causal Consistency:Ensure the Correct Order of Operations ===
const session = db.getMongo().startSession();
session.startTransaction({
  readConcern: { level: 'majority' },
  writeConcern: { w: 'majority' }
});

// Operation 1:Read the current balance
const account = db.accounts.findOne({ userId: 'user_001' }, { session });
// Operation 2:Write Based on Read Results
db.accounts.updateOne(
  { userId: 'user_001' },
  { $set: { balance: account.balance - 100 } },
  { session }
);
// Guarantee:Operation 2 What you see is the operation 1 Subsequent Status

Análise dos pontos-chave:

  1. Para garantir a consistência causal, é necessário usar uma sessão, e tanto readConcern quanto writeConcern devem ser definidos como majority.
  2. Ao realizar leituras entre nós (readPreference: secondary), a consistência causal garante que a leitura reflita a gravação feita pelo nó local.
  3. A consistência causal é o mecanismo subjacente às transações com múltiplos documentos e aos Change Streams do MongoDB.

▶ Exemplo: E-commerce Order com Payment e Inventory Deduction (Difficulty ⭐⭐)

JAVASCRIPT
// Scene: ShopHub checkout - reserve inventory, create order, deduct payment atomically
const mongoose = require('mongoose');
const session = await mongoose.startSession();
session.startTransaction();

try {
  const Product = mongoose.model('Product');
  const Order = mongoose.model('Order');
  const User = mongoose.model('User');

  const userId = 'user_001';
  const items = [
    { productId: 'prod_001', sku: 'PHONE-001', qty: 2, price: 599 },
    { productId: 'prod_002', sku: 'BOOK-001', qty: 1, price: 29 }
  ];
  const totalAmount = 1227;

  // Step 1: Check and reserve inventory (with pessimistic lock)
  for (const item of items) {
    const product = await Product.findOneAndUpdate(
      { _id: item.productId, stock: { $gte: item.qty } },
      { $inc: { stock: -item.qty } },
      { session, new: true }
    );
    if (!product) {
      throw new Error(`Insufficient stock for ${item.sku}`);
    }
  }

  // Step 2: Deduct user balance
  const user = await User.findOneAndUpdate(
    { _id: userId, balance: { $gte: totalAmount } },
    { $inc: { balance: -totalAmount } },
    { session, new: true }
  );
  if (!user) {
    throw new Error('Insufficient balance');
  }

  // Step 3: Create order
  const order = await Order.create([{
    userId,
    items,
    total: totalAmount,
    status: 'paid',
    paidAt: new Date()
  }], { session });

  await session.commitTransaction();
  console.log('Order created:', order[0]._id);
} catch (err) {
  await session.abortTransaction();
  console.error('Transaction failed:', err.message);
} finally {
  session.endSession();
}

Saída:

TEXT 📖 Somente leitura
Order created: 67890abcdef12345
// OR on failure:
Transaction failed: Insufficient stock for PHONE-001

▶ Exemplo: Um guia prático completo sobre transações de pedidos no comércio eletrônico

JAVASCRIPT
// Scene: Order placement process (Order + Inventory Deduction + Wallet Deduction + Logging), Fully Atomic
// Introduction: A replica set is required. Transactions must be in progress

// Initialize Data
db.products.insertOne({ sku: 'PHONE-001', stock: 10, price: 599 });
db.users.insertOne({ _id: 'user_001', balance: 1000 });
db.transaction_logs.createIndex({ userId: 1, createdAt: -1 });

// Complete Transaction Functions
async function placeOrder(userId, items) {
  const session = db.getMongo().startSession();
  session.startTransaction({
    readConcern: { level: 'snapshot' },
    writeConcern: { w: 'majority' }
  });

  try {
    // 1. Calculate the total amount + Check Inventory (Atomic Read)
    let total = 0;
    for (const item of items) {
      const product = db.products.findOne(
        { sku: item.sku, stock: { $gte: item.qty } },
        { session }
      );
      if (!product) {
        throw new Error(`Out of Stock: ${item.sku}`);
      }
      total += product.price * item.qty;
    }

    // 2. Check User Balance
    const user = db.users.findOne({ _id: userId }, { session });
    if (user.balance < total) {
      throw new Error('Insufficient balance');
    }

    // 3. Inventory Deduction (Conditional, Preventing Overselling)
    for (const item of items) {
      const result = db.products.updateOne(
        { sku: item.sku, stock: { $gte: item.qty } },
        { $inc: { stock: -item.qty } },
        { session }
      );
      if (result.modifiedCount === 0) {
        throw new Error(`Inventory deduction failed: ${item.sku}`);
      }
    }

    // 4. Deduct from the user's balance
    db.users.updateOne(
      { _id: userId, balance: { $gte: total } },
      { $inc: { balance: -total } },
      { session }
    );

    // 5. Create an Order
    const orderResult = db.orders.insertOne({
      userId,
      items,
      total,
      status: 'paid',
      createdAt: new Date()
    }, { session });

    // 6. Record the transaction log
    db.transaction_logs.insertOne({
      userId,
      orderId: orderResult.insertedId,
      amount: total,
      type: 'purchase',
      createdAt: new Date()
    }, { session });

    // 7. Commit Transaction
    session.commitTransaction();
    return { success: true, orderId: orderResult.insertedId };

  } catch (err) {
    // Any failure → Roll Back All
    session.abortTransaction();
    return { success: false, error: err.message };
  } finally {
    session.endSession();
  }
}

// Execute: Place an Order
placeOrder('user_001', [
  { sku: 'PHONE-001', qty: 1 }
]);

// Testing Rollback Scenarios: Deliberately Creating Errors
placeOrder('user_001', [
  { sku: 'NONEXIST', qty: 1 }  // The product does not exist.
]);
// Throw an exception → Transaction Rollback → Inventory, balance, order, all logs remain unchanged

// Verifying Atomicity:
// db.products.findOne({ sku: 'PHONE-001' }) → stock: 10 (Not deducted)
// db.users.findOne({ _id: 'user_001' }) → balance: 1000 (Not deducted)

Resultado: Quando uma transação é bem-sucedida, todas as alterações são confirmadas de uma só vez; quando uma transação falha, todas as alterações são revertidas, garantindo a consistência dos dados.

❓ Perguntas Frequentes

P: Uma transação pode garantir consistência de dados forte? R: Com um conjunto de réplicas + writeConcern maioria + readConcern maioria + readPreference primário, sim.

P: Em quanto o desempenho das transações fica prejudicado? R: É 30 a 50% mais lento do que as operações não transacionais. As transações envolvem bloqueios e instantâneos.

P: Uma instância do MongoDB com um único nó pode usar transações? R: Não. É necessário que seja um conjunto de réplicas ou um cluster fragmentado.


📖 Resumo


📝 Exercícios

  1. Questão básica (⭐): Implemente uma transação de transferência usando o mongosh (incluindo try-catch e rollback).
  2. Problema básico (⭐): Use o Mongoose para encapsular a função utilitária withTransaction.
  3. Exercício avançado (⭐⭐): Implemente uma transação de pedido (fazer o pedido + deduzir do estoque + criar o pedido + esvaziar o carrinho de compras — tudo de forma atômica).
  4. Exercício avançado (⭐⭐): Teste a reversão da transação em caso de falha (gerar um erro intencionalmente para verificar a atomicidade).
  5. Desafio (⭐⭐⭐): Desenvolva um sistema completo de transações de comércio eletrônico (pedidos + estoque + carteira + registros) que suporte a reversão distribuída.
Web-Tutorial.com

Equipe Técnica Web-Tutorial

Uma plataforma de tutoriais mantida por diversos desenvolvedores. Cada tutorial é escrito e revisado por profissionais da área correspondente. Trabalhamos para manter nosso conteúdo preciso e confiável — se encontrar algum problema, avise-nos.

100%