Menu Docs
Página inicial do Docs
/ / /
Node.js
/

Transações

Nesta página

  • Visão geral
  • APIs de transações
  • Core API
  • Configurações de transação
  • Exemplos
  • Dados de amostra
  • Implementação da Core API
  • Resultado da transação de pagamento

Leia este guia para saber como realizar transação no MongoDB usando o driver Node.js. A transaction is a unit of work, composed of a series of operations that you want either to succeed together, or fail together when one or more of the operations fail. Esse comportamento é chamado de atomicidade. Atomicidade é uma propriedade na qual transação compostas de uma ou mais operações ocorrem de uma só vez, de modo que nenhum outro cliente possa observá-las como operações separadas, e que não deixa alterações se uma das operações falhar.

Como todas as operações de gravação em um único documento no MongoDB são atômicas, você pode se beneficiar mais das transações quando precisar fazer uma alteração atômica que modifique vários documentos, o que é chamado de transação multidocumento. Semelhante às operações de gravação em um único documento, as transações de vários documentos são compatíveis com ACID, o que significa que o MongoDB garante que os dados envolvidos em suas operações de transação permaneçam consistentes, mesmo que encontrem erros inesperados. Saiba mais neste artigo do MongoDB sobre transações ACID.

Você pode usar o driver para realizar transação com vários documento.

Observação

Para executar transação de vários documentos, você deve usar o MongoDB versão 4.0 ou posterior.

Para obter uma lista detalhada das limitações, consulte a seção Transações e operações no manual do servidor.

No MongoDB, transações de vários documentos são executadas dentro de uma sessão de cliente. Uma sessão de cliente é um agrupamento de operações de leitura ou escrita relacionadas que você deseja garantir a execução sequencial. Recomendamos que você reutilize seu cliente para várias sessões e transações, em vez de fazer a instância de um novo cliente a cada vez.

Quando combinado com as preocupações de leitura e escrita da maioria, o driver pode garantir consistência causal entre as operações. Consulte o guia do manual do servidor sobre Sessões de cliente e garantias de consistência causal para obter mais informações.

Saiba mais sobre como usar o driver para executar transação de vários documento no MongoDB nas seguintes seções deste guia:

Use a Core API para implementar uma transação com o driver. Para usar a Core API, você declara o ponto de início e confirmação da transação.

A Core API apresenta métodos para iniciar, cancelar ou confirmar uma transação. Ao confirmar a transação, você envia uma solicitação ao servidor para fazer as alterações de suas operações atomicamente. Ao usar essa API, você deve lidar com determinados erros de transação retornados pelo servidor manualmente.

Consulte TransientTransactionError e UnknownTransactionCommitResult para obter mais informações sobre esses erros.

Para iniciar, cancelar ou confirmar sua transação, você pode chamar o método correspondente no objeto Session :

  • startTransaction()

  • commitTransaction()

  • abortTransaction()

Veja o exemplo daCore API para ver um exemplo de implementação de transação.

Ao instanciar uma transação, você pode especificar as seguintes opções para definir o comportamento padrão para essa transação:

Contexto
Descrição
readConcern

Especifica como verificar a consistência dos dados que as operações de leitura recuperam dos conjuntos de réplicas.

Consulte Read Concern no manual do servidor para obter mais informações.

writeConcern
Especifica as condições para confirmar a gravação. Consulte Write Concern no manual do servidor para obter mais informações.
readPreference
Consulte Preferência de leitura no manual do servidor para obter mais informações.
maxCommitTimeMS
Especifica a quantidade máxima de tempo para permitir que uma ação de confirmação em uma transação seja executada em milissegundos.

Se você não fornecer valores, o driver usará as configurações do cliente.

Você pode especificar as opções de transação na Core API usando um código semelhante ao seguinte:

const transactionOptions = {
readPreference: 'primary',
readConcern: { level: 'local' },
writeConcern: { w: 'majority' },
maxCommitTimeMS: 1000
};
session.startTransaction(transactionOptions);

Considere um cenário em que um cliente compra itens de sua loja online. Para registrar a compra, seu aplicativo precisa atualizar as informações relacionadas ao estoque, aos pedidos do cliente e registrar os detalhes do pedido. Suponha que você organize as atualizações de dados da seguinte maneira:

collection
(operação)
Descrição da alteração
orders
insert
Registre as informações de compra
customers
update
Anexe o ID do pedido para associá-lo ao cliente
inventory
update
Subtrair a quantidade de itens pedidos

Uma compra pode falhar de várias maneiras, como se houver quantidade insuficiente do item no estoque, se o pedido não puder ser concluído ou se o sistema de pagamento estiver off-line.

Se o pagamento falhar, você poderá usar uma transação para evitar a exposição de atualizações parciais que possam causar problemas de consistência de dados para outras operações que dependem desses dados.

Os exemplos de código exigem os seguintes dados de exemplo no reconhecimento de data center testdb para executar a transação de pagamento de vários documento:

  • Um documento na collection customers que descreve um cliente e seus pedidos.

  • documento na collection inventory que cada quantidade da faixa e descrição de um item.

O documento na collection customers neste exemplo contém o seguinte:

{ _id: 98765, orders: [] }

O documento na collection inventory neste exemplo contêm o seguinte:

[
{ name: "sunblock", sku: 5432, qty: 85 },
{ name: "beach towel", sku: 7865, qty: 41 }
]

Os exemplos de código também executam operações na collection orders , mas não exigem nenhum documento de amostra anterior.

Os exemplos de código usam as variáveis cart e payment para representar uma lista de amostra de itens comprados e os detalhes de pagamento do pedido da seguinte forma:

const cart = [
{ name: 'sunblock', sku: 5432, qty: 1, price: 5.19 },
{ name: 'beach towel', sku: 7865, qty: 2, price: 15.99 }
];
const payment = { customer: 98765, total: 37.17 };

Importante

Os exemplos nas seções a seguir exigem que você crie as collections fora da transação ou que esteja usando o MongoDB 4.4 ou posterior. Para obter mais informações sobre como criar coleções dentro de uma transação, consulte o guia Criar coleções e índices em um servidor de transação .

O exemplo de código nesta seção demonstra como você pode usar a Core API para executar a transação de pagamento de vários documentos em uma sessão. Esta função mostra como você pode executar o seguinte:

  1. Iniciar uma sessão

  2. Iniciar uma transação, especificando as opções de transação

  3. Executar operações de dados na mesma sessão

  4. Confirmar uma transação ou cancelá-la se o driver encontrar um erro

  5. Encerrar uma sessão

1async function placeOrder(client, cart, payment) {
2 const transactionOptions = {
3 readConcern: { level: 'snapshot' },
4 writeConcern: { w: 'majority' },
5 readPreference: 'primary'
6 };
7
8 const session = client.startSession();
9 try {
10 session.startTransaction(transactionOptions);
11
12 const ordersCollection = client.db('testdb').collection('orders');
13 const orderResult = await ordersCollection.insertOne(
14 {
15 customer: payment.customer,
16 items: cart,
17 total: payment.total,
18 },
19 { session }
20 );
21
22 const inventoryCollection = client.db('testdb').collection('inventory');
23 for (let i=0; i<cart.length; i++) {
24 const item = cart[i];
25
26 // Cancel the transaction when you have insufficient inventory
27 const checkInventory = await inventoryCollection.findOne(
28 {
29 sku: item.sku,
30 qty: { $gte: item.qty }
31 },
32 { session }
33 )
34 if (checkInventory === null) {
35 throw new Error('Insufficient quantity or SKU not found.');
36 }
37
38 await inventoryCollection.updateOne(
39 { sku: item.sku },
40 { $inc: { 'qty': -item.qty }},
41 { session }
42 );
43 }
44
45 const customerCollection = client.db('testdb').collection('customers');
46 await customerCollection.updateOne(
47 { _id: payment.customer },
48 { $push: { orders: orderResult.insertedId }},
49 { session }
50 );
51 await session.commitTransaction();
52 console.log('Transaction successfully committed.');
53
54 } catch (error) {
55 if (error instanceof MongoError && error.hasErrorLabel('UnknownTransactionCommitResult')) {
56 // add your logic to retry or handle the error
57 }
58 else if (error instanceof MongoError && error.hasErrorLabel('TransientTransactionError')) {
59 // add your logic to retry or handle the error
60 } else {
61 console.log('An error occured in the transaction, performing a data rollback:' + error);
62 }
63 await session.abortTransaction();
64 } finally {
65 await session.endSession();
66 }
67}

Observe que você deve passar o objeto de sessão para cada operação CRUD que deseja executar nessa sessão.

O código e os comentários no bloco catch demonstram como você pode identificar os erros de transação do servidor e onde você pode colocar sua lógica para lidar com eles. Certifique-se de incluir o tipo MongoError do driver em seu código, conforme mostrado na seguinte declaração de importação de exemplo:

const { MongoError, MongoClient } = require('mongodb');

Consulte a seção Resultado da transação de pagamento para ver o que suas coleções devem conter depois de executar a transação.

Se a sua aplicação concluir a transação de pagamento, o seu reconhecimento de data center deverá conter todas as atualizações e, se uma exceção interromper sua transação, nenhuma das alterações deverá existir no seu reconhecimento de data center.

A collection customers deve conter o documento do cliente com um ID anexado ao campo de pedidos:

{
"_id": 98765,
"orders": [
"61dc..."
]
}

A collection inventory deve conter quantidades atualizadas para os itens "sunblock" e "toalha de verão":

[
{
"_id": ...,
"name": "sunblock",
"sku": 5432,
"qty": 84
},
{
"_id": ...,
"name": "beach towel",
"sku": 7865,
"qty": 39
}
]

A collection orders deve conter as informações de pedido e pagamento:

[
{
"_id": "...",
"customer": 98765,
"items": [
{
"name": "sunblock",
"sku": 5432,
"qty": 1,
"price": 5.19
},
{
"name": "beach towel",
"sku": 7865,
"qty": 2,
"price": 15.99
}
],
"total": 37.17
}
]

Voltar

Agregação