Visão geral
Neste guia, você pode aprender a usar o driver Node.js para executar transações. As transações permitem que você execute uma série de operações que não alteram nenhum dado até que toda a transação seja confirmada. Se qualquer operação na transação falhar, o driver encerra a transação e descarta todas as alterações de dados antes que elas se tornem visíveis. Esse recurso é chamado de atomicidade.
Como todas as operações de gravação em um único documento no MongoDB são atômicas, convém usar transações para fazer uma alteração atômica que modifique vários documentos. Essa situação exige uma transação multidocumento. As transações de vários documentos são compatíveis com ACID porque o MongoDB garante que os dados envolvidos em suas operações de transação permaneçam consistentes, mesmo se o driver encontrar erros inesperados.
Para saber mais sobre conformidade com ACID e ACID transactions, consulte nosso artigo sobre transações ACID.
Observação
Para executar uma transação de vários documentos, você deve estar conectado a uma implementação executando o Servidor 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.
Saiba mais sobre como usar o driver para realizar transações com vários documentos nas seguintes seções deste guia:
Consistência causal
O MongoDB permite consistência causal em determinadas sessões de cliente. O modelo de consistência causal garante que, em um sistema distribuído, as operações dentro de uma sessão sejam executadas em uma ordem causal. Os clientes observam resultados consistentes com as relações causais ou as dependências entre as operações. Por exemplo, se você executar uma série de operações em que uma operação depende logicamente do resultado de outra, todas as leituras subsequentes refletirão o relacionamento de dependência .
Para garantir a consistência causal, as sessões de cliente devem atender aos seguintes requisitos:
Ao iniciar uma sessão, o driver deve habilitar a opção de consistência causal. Esta opção está habilitada por padrão.
As operações devem ser executadas em uma única sessão em um único thread. Caso contrário, as sessões ou threads devem comunicar os valores de optime e tempo de cluster uns aos outros. Para exibir um exemplo de duas sessões que comunicam esses valores, consulte os exemplos de Consistência causal no manual do MongoDB Server.
Você deve usar uma
majority
preocupação de leitura.Você deve usar uma preocupação de gravação
majority
. Este é o valor padrão de preocupação de gravação .
A tabela a seguir descreve as garantias que as sessões causalmente consistentes oferecem:
Garantia | Descrição |
---|---|
Ler suas gravações | As operações de leitura refletem os resultados das operações de gravação anteriores. |
Leituras monotônicas | As operações de leitura não retornam resultados que reflitam um estado de dados anterior a uma operação de leitura anterior. |
Escritas monotônicas | Se uma operação de gravação precisar preceder outras operações de gravação, o servidor executará essa operação de gravação primeiro. Por exemplo, se você chamar |
Escritas que seguem as leituras | Se uma operação de gravação precisar seguir outras operações de leitura, o servidor executará primeiro as operações de leitura. Por exemplo, se você chamar |
Dica
Para saber mais sobre os conceitos mencionados nesta seção, consulte as seguintes entradas de manual do MongoDB Server :
APIs de transações
O driver fornece duas APIs para realizar transações, a API Principal e a API de Transações Convenientes.
A API principal é uma estrutura que permite criar, confirmar e encerrar transações. Ao usar esta API, você deve executar explicitamente as seguintes ações:
Crie, confirme e encerre a transação.
Crie e finalize a sessão na qual você executa a transação.
Implemente lógica de tratamento de erros.
A Convenient Transaction API é uma estrutura que permite que você execute transações sem ser responsável por confirmá-las ou encerrá-las. Essa API incorpora automaticamente a lógica de tratamento de erros para tentar novamente as operações quando o servidor gera determinados tipos de erro. Para saber mais sobre esse comportamento, consulte a seção Erros de transação deste guia.
Importante
Quando você se conecta ao MongoDB Server versão 4.2 ou anterior, você pode executar operações de gravação em uma transação somente em coleções que já existem. Quando você se conecta ao MongoDB Server versão 4.4 e posterior, o servidor cria automaticamente coleções conforme necessário quando você executa operações de gravação em uma transação. Para saber mais sobre esse comportamento, consulte Criar coleções e índices em uma transação no manual do servidor.
Core API
A API central fornece os seguintes métodos para implementar transações:
startSession(): cria uma nova
ClientSession
instância dostartTransaction(): inicia uma nova transação
commitTransaction (): confirma a transação ativa na sessão em que ela foi criada
abortTransaction(): termina a transação ativa na sessão em que foi criada
endSession(): termina a sessão ativa
Você deve executar as seguintes etapas ao usar esta API:
Passe a instância de sessão para cada operação que deseja executar nessa sessão.
Implemente um bloco
catch
no qual você identifica erros de transação do servidor e implementa a lógica de tratamento de erros.
O código a seguir demonstra como realizar uma transação usando a API Central:
async function coreTest(client) { const session = client.startSession(); try { session.startTransaction(); const savingsColl = client.db("bank").collection("savings_accounts"); await savingsColl.findOneAndUpdate( {account_id: "9876"}, {$inc: {amount: -100 }}, { session }); const checkingColl = client.db("bank").collection("checking_accounts"); await checkingColl.findOneAndUpdate( {account_id: "9876"}, {$inc: {amount: 100 }}, { session }); // ... perform other operations await session.commitTransaction(); console.log("Transaction committed."); } catch (error) { console.log("An error occurred during the transaction:" + error); await session.abortTransaction(); } finally { await session.endSession(); } }
Importante
Usar uma Sessão com o Cliente Que a Iniciou
O driver lançará um erro se você fornecer uma sessão de uma instância de MongoClient
para uma instância de cliente diferente.
Por exemplo, o código a seguir gera um erro MongoInvalidArgumentError
porque cria uma instância ClientSession
do cliente client1
, mas fornece essa sessão ao cliente client2
para uma operação de gravação:
const session = client1.startSession(); client2.db('myDB').collection('myColl').insertOne({ name: 'Jane Eyre' }, { session });
Dica
Gerenciamento explícito de recursos
O driver Node.js suporta nativamente o gerenciamento explícito de recursos MongoClient
ClientSession
para,, ChangeStreams
e cursores. Este recurso é experimental e sujeito a alterações. Para saber como usar o gerenciamento explícito de recursos, consulte as Notas de versão do v.6.9
Para ver um exemplo totalmente executável que usa essa API, consulte o exemplo de uso Usar a Core API .
API de transação conveniente
A API de transação conveniente oferece os seguintes métodos para implementar transações:
withSession(): Executa a chamada de resposta passada em uma sessão. A API cuida da criação e do encerramento da sessão automaticamente.
withTransaction(): Executa a chamada de resposta passada a ela dentro de uma transação e chama o
commitTransaction()
método quando a chamada de resposta retorna.
Esses métodos retornam o valor que o retorno de chamada retorna. Por exemplo, se um retorno de chamada que você passar para o método withTransaction()
retornar o documento { hello: "world" }
, então o método withTransaction()
também retornará esse documento.
Importante
Para evitar erros de loop infinito, certifique-se de que a chamada de resposta de resposta que você passa para o método withTransaction()
capture todos os erros que ela gera.
Ao usar a API de transação conveniente, você pode propagar os valores de retorno da chamada de resposta como os valores de retorno dos métodos withTransaction()
e withSession()
para trabalhar com eles em outras partes do seu código.
Você deve executar as seguintes etapas ao usar esta API:
Passe a instância de sessão para cada operação que deseja executar nessa sessão.
Implemente a sintaxe assíncrona
await
para cada operação na sessão.Evite paralelismo, como chamar o método
Promise.all()
. Usar sessões em paralelo geralmente leva a erros no servidor.
O código a seguir demonstra como realizar uma transação usando a API de Transação Conveniente:
async function convTest(client) { let txnRes = await client.withSession(async (session) => session.withTransaction(async (session) => { const savingsColl = client.db("bank").collection("savings_accounts"); await savingsColl.findOneAndUpdate( {account_id: "9876"}, {$inc: {amount: -100 }}, { session }); const checkingColl = client.db("bank").collection("checking_accounts"); await checkingColl.findOneAndUpdate( {account_id: "9876"}, {$inc: {amount: 100 }}, { session }); // ... perform other operations return "Transaction committed."; }, null) ); console.log(txnRes); }
Para ver um exemplo totalmente executável que usa essa API, consulte o exemplo de uso API de transação conveniente.
Observação
Operações paralelas não suportadas
O driver Node.js não suporta a execução de operações paralelas dentro de uma única transação.
opções de transação
Você pode passar uma instância TransactionOptions
para os métodos startTransaction()
e withTransaction()
para configurar como o driver executa uma transação. Quando você especifica uma opção, ela substitui o valor da opção que você pode ter definido em sua instância MongoClient
.
A tabela seguinte inclui opções que você pode especificar em uma instância do TransactionOptions
:
Contexto | Descrição |
---|---|
| Specifies read operation consistency of the replica set. To learn more, see Read Concern in the Server manual. |
| Specifies the write operation level of acknowledgment required
from a replica set. To learn more, see Write Concern in the Server manual. |
| Specifies how to route read operations to members of a replica set. To learn more, see Read Preference in the Server manual. |
| Especifica o tempo de execução de uma ação de confirmação em uma transação, em milissegundos. |
Para obter uma lista completa de opções, consulte a documentação da API para TransactionOptions.
Observação
A transação herda as configurações de sua instância MongoClient
, a menos que você as especifique em suas opções de transação.
O código a seguir mostra como definir e passar as opções de transação para o método startTransaction()
:
const txnOpts = { readPreference: 'primary', readConcern: { level: 'local' }, writeConcern: { w: 'majority' }, maxCommitTimeMS: 1000 }; session.startTransaction(txnOpts);
Erros de transação
Como as transações do MongoDB são compatíveis com ACID, o driver pode produzir erros durante a operação para garantir que seus dados permaneçam consistentes. Se ocorrerem os seguintes erros, seu aplicação deverá tentar novamente a transação:
TransientTransactionError
: gerado se uma operação de gravação encontrar um erro antes do driver confirmar a transação. Para saber mais sobre esse tipo de erro, consulte a Descrição do TransientTransactionError na página API de Drivers no manual do Servidor.UnknownTransactionCommitResult
: Criado se a operação de commit encontrar um erro. Para saber mais sobre esse tipo de erro, consulte a Descrição do UnknownTransactionCommitResult na página API de Drivers no manual do Servidor.
As seções a seguir descrevem como lidar com esses erros ao usar APIs diferentes.
Tratamento Convenient Transaction API
A Convenient Transaction API incorpora a lógica de repetição para esses tipos de erro. O driver tenta novamente a transação automaticamente até que haja uma confirmação bem-sucedida.
Tratamento de erros da API principal
Se você estiver usando a API Central para executar uma transação, deverá adicionar as seguintes funções de tratamento de erros ao seu aplicação:
Uma função que tenta novamente toda a transação quando o motorista encontra um
TransientTransactionError
Uma função que tenta novamente a operação de confirmação quando o motorista encontra um
UnknownTransactionCommitResult
Essas funções devem ser executadas até que haja uma confirmação bem-sucedida ou um erro diferente. Para obter um exemplo dessa lógica de repetição, consulte a seção API principal na página API drivers no manual do servidor.