Session.startTransaction()
Nesta página
Definição
Session.startTransaction(<options>)
Inicia umatransação multidocumento associada à sessão. A qualquer momento, você pode ter no máximo uma transação aberta em uma sessão.
Observação
Esta operação é um no-op. A transação não iniciará no servidor até que o primeiro comando seja enviado na sessão. Portanto, o tempo de snapshot da transação não será definido até que o primeiro comando seja enviado na sessão.
Transações multidocumento estão disponíveis tanto para clusters fragmentados quanto para conjuntos de réplicas.
Importante
Em uma transação, você só pode especificar operações de leitura e gravação (CRUD) em collections existentes . Por exemplo, uma transação multidocumento não pode incluir uma operação de inserção que resultaria na criação de uma nova collection.
O método
Session.startTransaction()
pode levar um documento com as seguintes opções:{ readConcern: { level: <level>}, writeConcern: { w: <value>, j: <boolean>, wtimeout: <number> } } OpçãoDescriçãoreadConcern
Opcional. Um documento que especifica o read concern para todas as operações na transação, substituindo o read concern específico da operação.
Você pode especificar um dos seguintes níveis de read concern:
Para os read concerns
"local"
e"majority"
, o MongoDB pode, às vezes, substituir um read concern mais forte.writeConcern
Opcional. Um documento que especifica o write concern da transação. Essa write concern se aplica às operações de confirmação e anulação da transação.
As operações dentro da transação usam
"w: 1"
, substituindo o write concern específico da operação.Se você se comprometer usando
"w: 1"
write concern, sua transação poderá ser revertida durante o processo de failover.Para drivers do MongoDB, as transações usam o write concern no nível do cliente como padrão.
Compatibilidade
Esse método está disponível em implantações hospedadas nos seguintes ambientes:
MongoDB Atlas: o serviço totalmente gerenciado para implantações do MongoDB na nuvem
MongoDB Enterprise: a versão autogerenciada e baseada em assinatura do MongoDB
MongoDB Community: uma versão com código disponível, de uso gratuito e autogerenciada do MongoDB
Comportamento
Operações suportadas em uma transação
Observação
Se estiver executando com controle de acesso, você deverá ter privilégios para as operações na transação.
Para transações com vários documentos:
Você pode criar coleções e índices em transações. Para obter detalhes, consulte Crie coleções e índices em uma transação
A coletas utilizadas em uma transação podem estar em diferentes bancos de dados.
Observação
Você não pode criar uma nova coleta em transações de gravação entre fragmentos. Por exemplo, se você gravar em uma coleta existente em um fragmento e criar implicitamente uma coleta em um fragmento diferente, o MongoDB não poderá executar ambas as operações na mesma transação.
Você não pode gravar em coletas limitadas .
Não é possível usar read concern
"snapshot"
ao ler em uma capped collection. (A partir do MongoDB 5.0)Você não pode ler/gravar em coletas nos bancos de dados
config
,admin
oulocal
.Você não pode gravar na coleção
system.*
.Não é possível retornar o plano de query da operação compatível utilizando
explain
ou comandos semelhantes.
Para cursores criados fora de uma transação, você não pode chamar
getMore
dentro da transação.Para cursores criados em uma transação, não é possível chamar
getMore
fora da transação.
Você não pode especificar o comando como a primeira operação em
killCursors
uma transação.Além disso, se você executar o comando
killCursors
em uma transação, o servidor interromperá imediatamente os cursores especificados. Não espera que a transação seja confirmada.
Método | Comando | Observação |
---|---|---|
Excluindo os seguintes estágios: | ||
Disponível em coleções não partilhadas. For sharded collections, use the aggregation pipeline with the
$group stage. See Distinct Operation. | ||
Se a operação de atualização ou substituição for executada com Para obter mais detalhes,consulte Operações de administração. | ||
Se for executado em uma coleção inexistente, a coleção será criada implicitamente. Para obter mais detalhes,consulte Operações de administração. | ||
Se for executado em uma coleção inexistente, a coleção será criada implicitamente. Para obter mais detalhes,consulte Operações de administração. | ||
Se for executado em uma coleção inexistente, a coleção será criada implicitamente. Para obter mais detalhes,consulte Operações de administração. |
As operações que afetam o catálogo do banco de dados, como a criação ou eliminação de uma coleção ou de um índice, não são permitidas em transações multidocumento. Por exemplo, uma transação multidocumento não pode incluir uma operação de inserção que resultaria na criação de uma nova coleção. Consulte Operações restritas.
Comandos informativos, como hello
, buildInfo
, connectionStatus
(e seus métodos de ajuda) são permitidos em transações; no entanto, eles não podem ser a primeira operação na transação.
readPreference
As transações suportam read preference primary
.
Atomicidade
Enquanto a transação estiver aberta, nenhuma alteração de dados feita pelas operações na transação será visível fora da transação:
Quando uma transação é confirmada, todas as alterações de dados feitas na transação são salvas e visíveis fora da transação. Ou seja, uma transação não confirmará algumas de suas alterações enquanto reverte outras.
Até que uma transação seja confirmada, as alterações de dados feitas na transação não serão visíveis fora da transação.
No entanto, quando uma transação é gravada em vários fragmentos, nem todas as operações de leitura externas precisam esperar que o resultado da transação confirmada fique visível nos fragmentos. Por exemplo, se uma transação estiver comprometida e escrever 1 estiver visível no fragmento A, mas escrever 2 ainda não estiver visível no fragmento B, uma leitura externa em questão de leitura
"local"
poderá ler os resultados da escrita 1 sem ver a escrita 2.Quando uma transação é cancelada, todas as alterações de dados feitas pelas gravações na transação são descartadas sem nunca se tornarem visíveis, e a transação termina.
Exemplo
Considere um cenário em que, à medida que as alterações são feitas no registro de um funcionário no banco de dados hr
, você deseja garantir que a collection de events
no banco de dados reporting
esteja sincronizada com as alterações hr
. Ou seja, você deseja garantir que essas gravações sejam feitas como uma única transação, de modo que ambas as operações sejam bem-sucedidas ou não.
A collection employees
no banco de dados hr
tem os seguintes documentos:
{ "_id" : ObjectId("5af0776263426f87dd69319a"), "employee" : 3, "name" : { "title" : "Mr.", "name" : "Iba Ochs" }, "status" : "Active", "department" : "ABC" } { "_id" : ObjectId("5af0776263426f87dd693198"), "employee" : 1, "name" : { "title" : "Miss", "name" : "Ann Thrope" }, "status" : "Active", "department" : "ABC" } { "_id" : ObjectId("5af0776263426f87dd693199"), "employee" : 2, "name" : { "title" : "Mrs.", "name" : "Eppie Delta" }, "status" : "Active", "department" : "XYZ" }
A collection events
no banco de dados reporting
tem os seguintes documentos:
{ "_id" : ObjectId("5af07daa051d92f02462644a"), "employee" : 1, "status" : { "new" : "Active", "old" : null }, "department" : { "new" : "ABC", "old" : null } } { "_id" : ObjectId("5af07daa051d92f02462644b"), "employee" : 2, "status" : { "new" : "Active", "old" : null }, "department" : { "new" : "XYZ", "old" : null } } { "_id" : ObjectId("5af07daa051d92f02462644c"), "employee" : 3, "status" : { "new" : "Active", "old" : null }, "department" : { "new" : "ABC", "old" : null } }
O exemplo a seguir abre uma transação, atualiza o status de um funcionário para Inactive
no status employees
, insere um documento correspondente à collection events
e comete as duas operações como uma única transação.
// Runs the txnFunc and retries if TransientTransactionError encountered function runTransactionWithRetry(txnFunc, session) { while (true) { try { txnFunc(session); // performs transaction break; } catch (error) { // If transient error, retry the whole transaction if (error?.errorLabels?.includes("TransientTransactionError") ) { print("TransientTransactionError, retrying transaction ..."); continue; } else { throw error; } } } } // Retries commit if UnknownTransactionCommitResult encountered function commitWithRetry(session) { while (true) { try { session.commitTransaction(); // Uses write concern set at transaction start. print("Transaction committed."); break; } catch (error) { // Can retry commit if (error?.errorLabels?.includes("UnknownTransactionCommitResult") ) { print("UnknownTransactionCommitResult, retrying commit operation ..."); continue; } else { print("Error during commit ..."); throw error; } } } } // Updates two collections in a transactions function updateEmployeeInfo(session) { employeesCollection = session.getDatabase("hr").employees; eventsCollection = session.getDatabase("reporting").events; session.startTransaction( { readConcern: { level: "snapshot" }, writeConcern: { w: "majority" } } ); try{ employeesCollection.updateOne( { employee: 3 }, { $set: { status: "Inactive" } } ); eventsCollection.insertOne( { employee: 3, status: { new: "Inactive", old: "Active" } } ); } catch (error) { print("Caught exception during transaction, aborting."); session.abortTransaction(); throw error; } commitWithRetry(session); } // Start a session. session = db.getMongo().startSession( { readPreference: { mode: "primary" } } ); try{ runTransactionWithRetry(updateEmployeeInfo, session); } catch (error) { // Do something with error } finally { session.endSession(); }