En MongoDB, una operación en un solo documento es atómica. Dado que se pueden usar documentos incrustados y matrices para capturar relaciones entre datos en una única estructura de documento, en lugar de normalizar entre múltiples documentos y colecciones, esta atomicidad de un solo documento elimina la necesidad de transacciones multidocumento en muchos casos prácticos.
Para situaciones que requieren atomicidad en las lecturas y escrituras de múltiples documentos (en una o varias colecciones), MongoDB admite transacciones. Las transacciones pueden utilizarse en múltiples operaciones, colecciones, bases de datos, documentos y fragmentos.
API de transacciones
➤ Use el menú desplegable Seleccione su idioma en la parte superior derecha para establecer el idioma del siguiente ejemplo.
Este ejemplo resalta los componentes clave de la API de transacciones. En particular, utiliza la API de función de retorno. La API de función de retorno:
inicia una transacción
ejecuta las operaciones especificadas
confirma el resultado o finaliza la transacción en caso de error
Errores en las operaciones del lado del servidor, como el DuplicateKeyErrorPuede finalizar la transacción y generar un error de comando para alertar al usuario de que la transacción ha finalizado. Este comportamiento es previsible y ocurre incluso si el cliente nunca llama. Session.abortTransaction(). Para incorporar una gestión personalizada de errores, se debe usar la Core API en la transacción.
La callback API incorpora lógica de reintento para ciertos errores. El controlador intenta volver a ejecutar la transacción después de un TransientTransactionError o un error de confirmación UnknownTransactionCommitResult.
A partir del MongoDB 6.2, el servidor no vuelve a intentar la transacción si recibe un error TransactionTooLargeForCache.
A partir de MongoDB 8.1, si una operación upsert se ejecuta en una transacción de múltiples documentos, entonces upsert no vuelve a intentarlo cuando encuentra un error de clave duplicada.
Importante
Utilice el controlador de MongoDB para su versión de MongoDB.
Al usar drivers, cada operación en la transacción debe pasar la sesión a cada operación.
Las operaciones en una transacción utilizan preocupación de lectura a nivel de transacción,preocupación deescritura a nivel de transacción y preferenciade lectura a nivel de transacción.
Puedes crear colecciones en transacciones de forma implícita o explícita. Consulta Crear colecciones e índices en una transacción.
static bool with_transaction_example(bson_error_t *error) { mongoc_client_t *client = NULL; mongoc_write_concern_t *wc = NULL; mongoc_collection_t *coll = NULL; bool success = false; bool ret = false; bson_t *doc = NULL; bson_t *insert_opts = NULL; mongoc_client_session_t *session = NULL; mongoc_transaction_opt_t *txn_opts = NULL; /* For a replica set, include the replica set name and a seedlist of the * members in the URI string; e.g. * uri_repl = "mongodb://mongodb0.example.com:27017,mongodb1.example.com:" \ * "27017/?replicaSet=myRepl"; * client = mongoc_client_new (uri_repl); * For a sharded cluster, connect to the mongos instances; e.g. * uri_sharded = * "mongodb://mongos0.example.com:27017,mongos1.example.com:27017/"; * client = mongoc_client_new (uri_sharded); */ client = get_client(); /* Prereq: Create collections. Note Atlas connection strings include a majority write * concern by default. */ wc = mongoc_write_concern_new(); mongoc_write_concern_set_wmajority(wc, 1000); insert_opts = bson_new(); mongoc_write_concern_append(wc, insert_opts); coll = mongoc_client_get_collection(client, "mydb1", "foo"); doc = BCON_NEW("abc", BCON_INT32(0)); ret = mongoc_collection_insert_one(coll, doc, insert_opts, NULL /* reply */, error); if (!ret) { goto fail; } bson_destroy(doc); mongoc_collection_destroy(coll); coll = mongoc_client_get_collection(client, "mydb2", "bar"); doc = BCON_NEW("xyz", BCON_INT32(0)); ret = mongoc_collection_insert_one(coll, doc, insert_opts, NULL /* reply */, error); if (!ret) { goto fail; } /* Step 1: Start a client session. */ session = mongoc_client_start_session(client, NULL /* opts */, error); if (!session) { goto fail; } /* Step 2: Optional. Define options to use for the transaction. */ txn_opts = mongoc_transaction_opts_new(); mongoc_transaction_opts_set_write_concern(txn_opts, wc); /* Step 3: Use mongoc_client_session_with_transaction to start a transaction, * execute the callback, and commit (or abort on error). */ ret = mongoc_client_session_with_transaction(session, callback, txn_opts, NULL /* ctx */, NULL /* reply */, error); if (!ret) { goto fail; } success = true; fail: bson_destroy(doc); mongoc_collection_destroy(coll); bson_destroy(insert_opts); mongoc_write_concern_destroy(wc); mongoc_transaction_opts_destroy(txn_opts); mongoc_client_session_destroy(session); mongoc_client_destroy(client); return success; } /* Define the callback that specifies the sequence of operations to perform * inside the transactions. */ static bool callback(mongoc_client_session_t *session, void *ctx, bson_t **reply, bson_error_t *error) { mongoc_client_t *client = NULL; mongoc_collection_t *coll = NULL; bson_t *doc = NULL; bson_t *opts = bson_new(); bool success = false; bool ret = false; BSON_UNUSED(ctx); BSON_UNUSED(reply); // Important:: The logical session ID MUST be applied to all associated operations. ret = mongoc_client_session_append(session, opts, error); if (!ret) { goto fail; } client = mongoc_client_session_get_client(session); coll = mongoc_client_get_collection(client, "mydb1", "foo"); doc = BCON_NEW("abc", BCON_INT32(1)); ret = mongoc_collection_insert_one(coll, doc, opts, NULL, error); if (!ret) { goto fail; } bson_destroy(doc); mongoc_collection_destroy(coll); coll = mongoc_client_get_collection(client, "mydb2", "bar"); doc = BCON_NEW("xyz", BCON_INT32(999)); ret = mongoc_collection_insert_one(coll, doc, opts, NULL, error); if (!ret) { goto fail; } success = true; fail: mongoc_collection_destroy(coll); bson_destroy(opts); bson_destroy(doc); return success; }
Este ejemplo resalta los componentes clave de la API de transacciones. En particular, utiliza la API de función de retorno. La API de función de retorno:
inicia una transacción
ejecuta las operaciones especificadas
confirma el resultado o finaliza la transacción en caso de error
Los errores en las operaciones del lado del servidor, como el DuplicateKeyError, pueden finalizar la transacción y producir un error de comando para alertar al usuario de que la transacción ha terminado. Este comportamiento es esperado y ocurre incluso si el cliente nunca llama a Session.abortTransaction(). Para incorporar una gestión personalizada de errores, se debe usar la Core API en la transacción.
La callback API incorpora lógica de reintento para ciertos errores. El controlador intenta volver a ejecutar la transacción después de un TransientTransactionError o un error de confirmación UnknownTransactionCommitResult.
A partir del MongoDB 6.2, el servidor no vuelve a intentar la transacción si recibe un error TransactionTooLargeForCache.
A partir de MongoDB 8.1, si una operación upsert se ejecuta en una transacción de múltiples documentos, entonces upsert no vuelve a intentarlo cuando encuentra un error de clave duplicada.
Importante
Utilice el controlador de MongoDB para su versión de MongoDB.
Al usar drivers, cada operación en la transacción debe pasar la sesión a cada operación.
Las operaciones en una transacción utilizan nivel de consistencia de lectura a nivel de transacción, nivel de confirmación de escritura a nivel de transacción y preferencia de lectura a nivel de transacción.
Puedes crear colecciones en transacciones de forma implícita o explícita. Consulta Crear colecciones e índices en una transacción.
// The mongocxx::instance constructor and destructor initialize and shut down the driver, // respectively. Therefore, a mongocxx::instance must be created before using the driver and // must remain alive for as long as the driver is in use. mongocxx::instance inst{}; // For a replica set, include the replica set name and a seedlist of the members in the URI // string; e.g. // uriString = // 'mongodb://mongodb0.example.com:27017,mongodb1.example.com:27017/?replicaSet=myRepl' // For a sharded cluster, connect to the mongos instances; e.g. // uriString = 'mongodb://mongos0.example.com:27017,mongos1.example.com:27017/' mongocxx::client client{mongocxx::uri{}}; // Prepare to set majority write explicitly. Note: on Atlas deployments this won't always be // needed. The suggested Atlas connection string includes majority write concern by default. write_concern wc_majority{}; wc_majority.acknowledge_level(write_concern::level::k_majority); // Prereq: Create collections. auto foo = client["mydb1"]["foo"]; auto bar = client["mydb2"]["bar"]; try { options::insert opts; opts.write_concern(wc_majority); foo.insert_one(make_document(kvp("abc", 0)), opts); bar.insert_one(make_document(kvp("xyz", 0)), opts); } catch (mongocxx::exception const& e) { std::cout << "An exception occurred while inserting: " << e.what() << std::endl; return EXIT_FAILURE; } // Step 1: Define the callback that specifies the sequence of operations to perform inside the // transactions. client_session::with_transaction_cb callback = [&](client_session* session) { // Important:: You must pass the session to the operations. foo.insert_one(*session, make_document(kvp("abc", 1))); bar.insert_one(*session, make_document(kvp("xyz", 999))); }; // Step 2: Start a client session auto session = client.start_session(); // Step 3: Use with_transaction to start a transaction, execute the callback, // and commit (or abort on error). try { options::transaction opts; opts.write_concern(wc_majority); session.with_transaction(callback, opts); } catch (mongocxx::exception const& e) { std::cout << "An exception occurred: " << e.what() << std::endl; return EXIT_FAILURE; } return EXIT_SUCCESS;
Este ejemplo resalta los componentes clave de la API de transacciones. En particular, utiliza la API de función de retorno. La API de función de retorno:
inicia una transacción
ejecuta las operaciones especificadas
confirma el resultado o finaliza la transacción en caso de error
Los errores en las operaciones del lado del servidor, como el DuplicateKeyError, pueden finalizar la transacción y producir un error de comando para alertar al usuario de que la transacción ha terminado. Este comportamiento es esperado y ocurre incluso si el cliente nunca llama a Session.abortTransaction(). Para incorporar una gestión personalizada de errores, se debe usar la Core API en la transacción.
La callback API incorpora lógica de reintento para ciertos errores. El controlador intenta volver a ejecutar la transacción después de un TransientTransactionError o un error de confirmación UnknownTransactionCommitResult.
A partir del MongoDB 6.2, el servidor no vuelve a intentar la transacción si recibe un error TransactionTooLargeForCache.
A partir de MongoDB 8.1, si una operación upsert se ejecuta en una transacción de múltiples documentos, entonces upsert no vuelve a intentarlo cuando encuentra un error de clave duplicada.
Importante
Utilice el controlador de MongoDB para su versión de MongoDB.
Al usar drivers, cada operación en la transacción debe pasar la sesión a cada operación.
Las operaciones en una transacción utilizan nivel de consistencia de lectura a nivel de transacción, nivel de confirmación de escritura a nivel de transacción y preferencia de lectura a nivel de transacción.
Puedes crear colecciones en transacciones de forma implícita o explícita. Consulta Crear colecciones e índices en una transacción.
// For a replica set, include the replica set name and a seedlist of the members in the URI string; e.g. // string uri = "mongodb://mongodb0.example.com:27017,mongodb1.example.com:27017/?replicaSet=myRepl"; // For a sharded cluster, connect to the mongos instances; e.g. // string uri = "mongodb://mongos0.example.com:27017,mongos1.example.com:27017/"; var client = new MongoClient(connectionString); // Prereq: Create collections. var database1 = client.GetDatabase("mydb1"); var collection1 = database1.GetCollection<BsonDocument>("foo").WithWriteConcern(WriteConcern.WMajority); collection1.InsertOne(new BsonDocument("abc", 0)); var database2 = client.GetDatabase("mydb2"); var collection2 = database2.GetCollection<BsonDocument>("bar").WithWriteConcern(WriteConcern.WMajority); collection2.InsertOne(new BsonDocument("xyz", 0)); // Step 1: Start a client session. using (var session = client.StartSession()) { // Step 2: Optional. Define options to use for the transaction. var transactionOptions = new TransactionOptions( writeConcern: WriteConcern.WMajority); // Step 3: Define the sequence of operations to perform inside the transactions var cancellationToken = CancellationToken.None; // normally a real token would be used result = session.WithTransaction( (s, ct) => { try { collection1.InsertOne(s, new BsonDocument("abc", 1), cancellationToken: ct); collection2.InsertOne(s, new BsonDocument("xyz", 999), cancellationToken: ct); } catch (MongoWriteException) { // Do something in response to the exception throw; // NOTE: You must rethrow the exception otherwise an infinite loop can occur. } return "Inserted into collections in different databases"; }, transactionOptions, cancellationToken); }
Este ejemplo resalta los componentes clave de la API de transacciones. En particular, utiliza la API de función de retorno. La API de función de retorno:
inicia una transacción
ejecuta las operaciones especificadas
confirma el resultado o finaliza la transacción en caso de error
Los errores en las operaciones del lado del servidor, como el DuplicateKeyError, pueden finalizar la transacción y producir un error de comando para alertar al usuario de que la transacción ha terminado. Este comportamiento es esperado y ocurre incluso si el cliente nunca llama a Session.abortTransaction(). Para incorporar una gestión personalizada de errores, se debe usar la Core API en la transacción.
La callback API incorpora lógica de reintento para ciertos errores. El controlador intenta volver a ejecutar la transacción después de un TransientTransactionError o un error de confirmación UnknownTransactionCommitResult.
A partir del MongoDB 6.2, el servidor no vuelve a intentar la transacción si recibe un error TransactionTooLargeForCache.
A partir de MongoDB 8.1, si una operación upsert se ejecuta en una transacción de múltiples documentos, entonces upsert no vuelve a intentarlo cuando encuentra un error de clave duplicada.
Importante
Utilice el controlador de MongoDB para su versión de MongoDB.
Al usar drivers, cada operación en la transacción debe pasar la sesión a cada operación.
Las operaciones en una transacción utilizan nivel de consistencia de lectura a nivel de transacción, nivel de confirmación de escritura a nivel de transacción y preferencia de lectura a nivel de transacción.
Puedes crear colecciones en transacciones de forma implícita o explícita. Consulta Crear colecciones e índices en una transacción.
// WithTransactionExample is an example of using the Session.WithTransaction function. func WithTransactionExample(ctx context.Context) error { // For a replica set, include the replica set name and a seedlist of the members in the URI string; e.g. // uri := "mongodb://mongodb0.example.com:27017,mongodb1.example.com:27017/?replicaSet=myRepl" // For a sharded cluster, connect to the mongos instances; e.g. // uri := "mongodb://mongos0.example.com:27017,mongos1.example.com:27017/" uri := mtest.ClusterURI() clientOpts := options.Client().ApplyURI(uri) client, err := mongo.Connect(clientOpts) if err != nil { return err } defer func() { _ = client.Disconnect(ctx) }() // Prereq: Create collections. wcMajority := writeconcern.Majority() wcMajorityCollectionOpts := options.Collection().SetWriteConcern(wcMajority) fooColl := client.Database("mydb1").Collection("foo", wcMajorityCollectionOpts) barColl := client.Database("mydb1").Collection("bar", wcMajorityCollectionOpts) // Step 1: Define the callback that specifies the sequence of operations to perform inside the transaction. callback := func(sesctx context.Context) (any, error) { // Important: You must pass sesctx as the Context parameter to the operations for them to be executed in the // transaction. if _, err := fooColl.InsertOne(sesctx, bson.D{{"abc", 1}}); err != nil { return nil, err } if _, err := barColl.InsertOne(sesctx, bson.D{{"xyz", 999}}); err != nil { return nil, err } return nil, nil } // Step 2: Start a session and run the callback using WithTransaction. session, err := client.StartSession() if err != nil { return err } defer session.EndSession(ctx) result, err := session.WithTransaction(ctx, callback) if err != nil { return err } log.Printf("result: %v\n", result) return nil }
Este ejemplo resalta los componentes clave de la API de transacciones. En particular, utiliza la API de función de retorno. La API de función de retorno:
inicia una transacción
ejecuta las operaciones especificadas
confirma el resultado o finaliza la transacción en caso de error
Los errores en las operaciones del lado del servidor, como el DuplicateKeyError, pueden finalizar la transacción y producir un error de comando para alertar al usuario de que la transacción ha terminado. Este comportamiento es esperado y ocurre incluso si el cliente nunca llama a Session.abortTransaction(). Para incorporar una gestión personalizada de errores, se debe usar la Core API en la transacción.
La callback API incorpora lógica de reintento para ciertos errores. El controlador intenta volver a ejecutar la transacción después de un TransientTransactionError o un error de confirmación UnknownTransactionCommitResult.
A partir del MongoDB 6.2, el servidor no vuelve a intentar la transacción si recibe un error TransactionTooLargeForCache.
A partir de MongoDB 8.1, si una operación upsert se ejecuta en una transacción de múltiples documentos, entonces upsert no vuelve a intentarlo cuando encuentra un error de clave duplicada.
Importante
Utilice el controlador de MongoDB para su versión de MongoDB.
Al usar drivers, cada operación en la transacción debe pasar la sesión a cada operación.
Las operaciones en una transacción utilizan nivel de consistencia de lectura a nivel de transacción, nivel de confirmación de escritura a nivel de transacción y preferencia de lectura a nivel de transacción.
Puedes crear colecciones en transacciones de forma implícita o explícita. Consulta Crear colecciones e índices en una transacción.
/* For a replica set, include the replica set name and a seedlist of the members in the URI string; e.g. String uri = "mongodb://mongodb0.example.com:27017,mongodb1.example.com:27017/admin?replicaSet=myRepl"; For a sharded cluster, connect to the mongos instances. For example: String uri = "mongodb://mongos0.example.com:27017,mongos1.example.com:27017:27017/admin"; */ final MongoClient client = MongoClients.create(uri); /* Create collections. */ client.getDatabase("mydb1").getCollection("foo") .withWriteConcern(WriteConcern.MAJORITY).insertOne(new Document("abc", 0)); client.getDatabase("mydb2").getCollection("bar") .withWriteConcern(WriteConcern.MAJORITY).insertOne(new Document("xyz", 0)); /* Step 1: Start a client session. */ final ClientSession clientSession = client.startSession(); /* Step 2: Optional. Define options to use for the transaction. */ TransactionOptions txnOptions = TransactionOptions.builder() .writeConcern(WriteConcern.MAJORITY) .build(); /* Step 3: Define the sequence of operations to perform inside the transactions. */ TransactionBody txnBody = new TransactionBody<String>() { public String execute() { MongoCollection<Document> coll1 = client.getDatabase("mydb1").getCollection("foo"); MongoCollection<Document> coll2 = client.getDatabase("mydb2").getCollection("bar"); /* Important:: You must pass the session to the operations. */ coll1.insertOne(clientSession, new Document("abc", 1)); coll2.insertOne(clientSession, new Document("xyz", 999)); return "Inserted into collections in different databases"; } }; try { /* Step 4: Use .withTransaction() to start a transaction, execute the callback, and commit (or abort on error). */ clientSession.withTransaction(txnBody, txnOptions); } catch (RuntimeException e) { // some error handling } finally { clientSession.close(); }
Este ejemplo resalta los componentes clave de la API de transacciones. En particular, utiliza la API de función de retorno. La API de función de retorno:
inicia una transacción
ejecuta las operaciones especificadas
confirma el resultado o finaliza la transacción en caso de error
Los errores en las operaciones del lado del servidor, como el DuplicateKeyError, pueden finalizar la transacción y producir un error de comando para alertar al usuario de que la transacción ha terminado. Este comportamiento es esperado y ocurre incluso si el cliente nunca llama a Session.abortTransaction(). Para incorporar una gestión personalizada de errores, se debe usar la Core API en la transacción.
La callback API incorpora lógica de reintento para ciertos errores. El controlador intenta volver a ejecutar la transacción después de un TransientTransactionError o un error de confirmación UnknownTransactionCommitResult.
A partir del MongoDB 6.2, el servidor no vuelve a intentar la transacción si recibe un error TransactionTooLargeForCache.
A partir de MongoDB 8.1, si una operación upsert se ejecuta en una transacción de múltiples documentos, entonces upsert no vuelve a intentarlo cuando encuentra un error de clave duplicada.
Importante
Utilice el controlador de MongoDB para su versión de MongoDB.
Al usar drivers, cada operación en la transacción debe pasar la sesión a cada operación.
Las operaciones en una transacción utilizan nivel de consistencia de lectura a nivel de transacción, nivel de confirmación de escritura a nivel de transacción y preferencia de lectura a nivel de transacción.
Puedes crear colecciones en transacciones de forma implícita o explícita. Consulta Crear colecciones e índices en una transacción.
# For a replica set, include the replica set name and a seedlist of the members in the URI string; e.g. # uriString = 'mongodb://mongodb0.example.com:27017,mongodb1.example.com:27017/?replicaSet=myRepl' # For a sharded cluster, connect to the mongos instances; e.g. # uriString = 'mongodb://mongos0.example.com:27017,mongos1.example.com:27017/' client = AsyncIOMotorClient(uriString) wc_majority = WriteConcern("majority", wtimeout=1000) # Prereq: Create collections. await client.get_database("mydb1", write_concern=wc_majority).foo.insert_one({"abc": 0}) await client.get_database("mydb2", write_concern=wc_majority).bar.insert_one({"xyz": 0}) # Step 1: Define the callback that specifies the sequence of operations to perform inside the transactions. async def callback(my_session): collection_one = my_session.client.mydb1.foo collection_two = my_session.client.mydb2.bar # Important:: You must pass the session to the operations. await collection_one.insert_one({"abc": 1}, session=my_session) await collection_two.insert_one({"xyz": 999}, session=my_session) # Step 2: Start a client session. async with await client.start_session() as session: # Step 3: Use with_transaction to start a transaction, execute the callback, and commit (or abort on error). await session.with_transaction( callback, read_concern=ReadConcern("local"), write_concern=wc_majority, read_preference=ReadPreference.PRIMARY, )
Este ejemplo resalta los componentes clave de la API de transacciones. En particular, utiliza la API de función de retorno. La API de función de retorno:
inicia una transacción
ejecuta las operaciones especificadas
confirma el resultado o finaliza la transacción en caso de error
Los errores en las operaciones del lado del servidor, como el DuplicateKeyError, pueden finalizar la transacción y producir un error de comando para alertar al usuario de que la transacción ha terminado. Este comportamiento es esperado y ocurre incluso si el cliente nunca llama a Session.abortTransaction(). Para incorporar una gestión personalizada de errores, se debe usar la Core API en la transacción.
La callback API incorpora lógica de reintento para ciertos errores. El controlador intenta volver a ejecutar la transacción después de un TransientTransactionError o un error de confirmación UnknownTransactionCommitResult.
A partir del MongoDB 6.2, el servidor no vuelve a intentar la transacción si recibe un error TransactionTooLargeForCache.
A partir de MongoDB 8.1, si una operación upsert se ejecuta en una transacción de múltiples documentos, entonces upsert no vuelve a intentarlo cuando encuentra un error de clave duplicada.
Importante
Utilice el controlador de MongoDB para su versión de MongoDB.
Al usar drivers, cada operación en la transacción debe pasar la sesión a cada operación.
Las operaciones en una transacción utilizan nivel de consistencia de lectura a nivel de transacción, nivel de confirmación de escritura a nivel de transacción y preferencia de lectura a nivel de transacción.
Puedes crear colecciones en transacciones de forma implícita o explícita. Consulta Crear colecciones e índices en una transacción.
// For a replica set, include the replica set name and a seedlist of the members in the URI string; e.g. // const uri = 'mongodb://mongodb0.example.com:27017,mongodb1.example.com:27017/?replicaSet=myRepl' // For a sharded cluster, connect to the mongos instances; e.g. // const uri = 'mongodb://mongos0.example.com:27017,mongos1.example.com:27017/' const client = new MongoClient(uri); await client.connect(); // Prereq: Create collections. await client .db('mydb1') .collection('foo') .insertOne({ abc: 0 }, { writeConcern: { w: 'majority' } }); await client .db('mydb2') .collection('bar') .insertOne({ xyz: 0 }, { writeConcern: { w: 'majority' } }); // Step 1: Start a Client Session const session = client.startSession(); // Step 2: Optional. Define options to use for the transaction const transactionOptions = { readPreference: 'primary', readConcern: { level: 'local' }, writeConcern: { w: 'majority' } }; // Step 3: Use withTransaction to start a transaction, execute the callback, and commit (or abort on error) // Note: The callback for withTransaction MUST be async and/or return a Promise. try { await session.withTransaction(async () => { const coll1 = client.db('mydb1').collection('foo'); const coll2 = client.db('mydb2').collection('bar'); // Important:: You must pass the session to the operations await coll1.insertOne({ abc: 1 }, { session }); await coll2.insertOne({ xyz: 999 }, { session }); }, transactionOptions); } finally { await session.endSession(); await client.close(); }
Este ejemplo resalta los componentes clave de la API de transacciones. En particular, utiliza la API de función de retorno. La API de función de retorno:
inicia una transacción
ejecuta las operaciones especificadas
confirma el resultado o finaliza la transacción en caso de error
Los errores en las operaciones del lado del servidor, como el DuplicateKeyError, pueden finalizar la transacción y producir un error de comando para alertar al usuario de que la transacción ha terminado. Este comportamiento es esperado y ocurre incluso si el cliente nunca llama a Session.abortTransaction(). Para incorporar una gestión personalizada de errores, se debe usar la Core API en la transacción.
La callback API incorpora lógica de reintento para ciertos errores. El controlador intenta volver a ejecutar la transacción después de un TransientTransactionError o un error de confirmación UnknownTransactionCommitResult.
A partir del MongoDB 6.2, el servidor no vuelve a intentar la transacción si recibe un error TransactionTooLargeForCache.
A partir de MongoDB 8.1, si una operación upsert se ejecuta en una transacción de múltiples documentos, entonces upsert no vuelve a intentarlo cuando encuentra un error de clave duplicada.
Importante
Utilice el controlador de MongoDB para su versión de MongoDB.
Al usar drivers, cada operación en la transacción debe pasar la sesión a cada operación.
Las operaciones en una transacción utilizan nivel de consistencia de lectura a nivel de transacción, nivel de confirmación de escritura a nivel de transacción y preferencia de lectura a nivel de transacción.
Puedes crear colecciones en transacciones de forma implícita o explícita. Consulta Crear colecciones e índices en una transacción.
sub runTransactionWithRetry { my ( $txnFunc, $session ) = @_; LOOP: { eval { $txnFunc->($session); # performs transaction }; if ( my $error = $@ ) { print("Transaction aborted-> Caught exception during transaction.\n"); # If transient error, retry the whole transaction if ( $error->has_error_label("TransientTransactionError") ) { print("TransientTransactionError, retrying transaction ->..\n"); redo LOOP; } else { die $error; } } } return; } sub commitWithRetry { my ($session) = @_; LOOP: { eval { $session->commit_transaction(); # Uses write concern set at transaction start. print("Transaction committed->\n"); }; if ( my $error = $@ ) { # Can retry commit if ( $error->has_error_label("UnknownTransactionCommitResult") ) { print("UnknownTransactionCommitResult, retrying commit operation ->..\n"); redo LOOP; } else { print("Error during commit ->..\n"); die $error; } } } return; } # Updates two collections in a transactions sub updateEmployeeInfo { my ($session) = @_; my $employeesCollection = $session->client->ns("hr.employees"); my $eventsCollection = $session->client->ns("reporting.events"); $session->start_transaction( { readConcern => { level => "snapshot" }, writeConcern => { w => "majority" }, readPreference => 'primary', } ); eval { $employeesCollection->update_one( { employee => 3 }, { '$set' => { status => "Inactive" } }, { session => $session}, ); $eventsCollection->insert_one( { employee => 3, status => { new => "Inactive", old => "Active" } }, { session => $session}, ); }; if ( my $error = $@ ) { print("Caught exception during transaction, aborting->\n"); $session->abort_transaction(); die $error; } commitWithRetry($session); } # Start a session my $session = $client->start_session(); eval { runTransactionWithRetry(\&updateEmployeeInfo, $session); }; if ( my $error = $@ ) { # Do something with error } $session->end_session();
Este ejemplo resalta los componentes clave de la API de transacciones. En particular, utiliza la API de función de retorno. La API de función de retorno:
inicia una transacción
ejecuta las operaciones especificadas
confirma el resultado o finaliza la transacción en caso de error
Los errores en las operaciones del lado del servidor, como el DuplicateKeyError, pueden finalizar la transacción y producir un error de comando para alertar al usuario de que la transacción ha terminado. Este comportamiento es esperado y ocurre incluso si el cliente nunca llama a Session.abortTransaction(). Para incorporar una gestión personalizada de errores, se debe usar la Core API en la transacción.
La callback API incorpora lógica de reintento para ciertos errores. El controlador intenta volver a ejecutar la transacción después de un TransientTransactionError o un error de confirmación UnknownTransactionCommitResult.
A partir del MongoDB 6.2, el servidor no vuelve a intentar la transacción si recibe un error TransactionTooLargeForCache.
A partir de MongoDB 8.1, si una operación upsert se ejecuta en una transacción de múltiples documentos, entonces upsert no vuelve a intentarlo cuando encuentra un error de clave duplicada.
Importante
Utilice el controlador de MongoDB para su versión de MongoDB.
Al usar drivers, cada operación en la transacción debe pasar la sesión a cada operación.
Las operaciones en una transacción utilizan nivel de consistencia de lectura a nivel de transacción, nivel de confirmación de escritura a nivel de transacción y preferencia de lectura a nivel de transacción.
Puedes crear colecciones en transacciones de forma implícita o explícita. Consulta Crear colecciones e índices en una transacción.
/* * For a replica set, include the replica set name and a seedlist of the members in the URI string; e.g. * uriString = 'mongodb://mongodb0.example.com:27017,mongodb1.example.com:27017/?replicaSet=myRepl' * For a sharded cluster, connect to the mongos instances; e.g. * uriString = 'mongodb://mongos0.example.com:27017,mongos1.example.com:27017/' */ $client = new \MongoDB\Client($uriString); // Prerequisite: Create collections. $client->selectCollection( 'mydb1', 'foo', [ 'writeConcern' => new \MongoDB\Driver\WriteConcern(\MongoDB\Driver\WriteConcern::MAJORITY, 1000), ], )->insertOne(['abc' => 0]); $client->selectCollection( 'mydb2', 'bar', [ 'writeConcern' => new \MongoDB\Driver\WriteConcern(\MongoDB\Driver\WriteConcern::MAJORITY, 1000), ], )->insertOne(['xyz' => 0]); // Step 1: Define the callback that specifies the sequence of operations to perform inside the transactions. $callback = function (\MongoDB\Driver\Session $session) use ($client): void { $client ->selectCollection('mydb1', 'foo') ->insertOne(['abc' => 1], ['session' => $session]); $client ->selectCollection('mydb2', 'bar') ->insertOne(['xyz' => 999], ['session' => $session]); }; // Step 2: Start a client session. $session = $client->startSession(); // Step 3: Use with_transaction to start a transaction, execute the callback, and commit (or abort on error). \MongoDB\with_transaction($session, $callback);
Este ejemplo resalta los componentes clave de la API de transacciones. En particular, utiliza la API de función de retorno. La API de función de retorno:
inicia una transacción
ejecuta las operaciones especificadas
confirma el resultado o finaliza la transacción en caso de error
Los errores en las operaciones del lado del servidor, como el DuplicateKeyError, pueden finalizar la transacción y producir un error de comando para alertar al usuario de que la transacción ha terminado. Este comportamiento es esperado y ocurre incluso si el cliente nunca llama a Session.abortTransaction(). Para incorporar una gestión personalizada de errores, se debe usar la Core API en la transacción.
La callback API incorpora lógica de reintento para ciertos errores. El controlador intenta volver a ejecutar la transacción después de un TransientTransactionError o un error de confirmación UnknownTransactionCommitResult.
A partir del MongoDB 6.2, el servidor no vuelve a intentar la transacción si recibe un error TransactionTooLargeForCache.
A partir de MongoDB 8.1, si una operación upsert se ejecuta en una transacción de múltiples documentos, entonces upsert no vuelve a intentarlo cuando encuentra un error de clave duplicada.
Importante
Utilice el controlador de MongoDB para su versión de MongoDB.
Al usar drivers, cada operación en la transacción debe pasar la sesión a cada operación.
Las operaciones en una transacción utilizan nivel de consistencia de lectura a nivel de transacción, nivel de confirmación de escritura a nivel de transacción y preferencia de lectura a nivel de transacción.
Puedes crear colecciones en transacciones de forma implícita o explícita. Consulta Crear colecciones e índices en una transacción.
# For a replica set, include the replica set name and a seedlist of the members in the URI string; e.g. # uriString = 'mongodb://mongodb0.example.com:27017,mongodb1.example.com:27017/?replicaSet=myRepl' # For a sharded cluster, connect to the mongos instances; e.g. # uriString = 'mongodb://mongos0.example.com:27017,mongos1.example.com:27017/' client = MongoClient(uriString) wc_majority = WriteConcern("majority", wtimeout=1000) # Prereq: Create collections. client.get_database("mydb1", write_concern=wc_majority).foo.insert_one({"abc": 0}) client.get_database("mydb2", write_concern=wc_majority).bar.insert_one({"xyz": 0}) # Step 1: Define the callback that specifies the sequence of operations to perform inside the transactions. def callback(session): collection_one = session.client.mydb1.foo collection_two = session.client.mydb2.bar # Important:: You must pass the session to the operations. collection_one.insert_one({"abc": 1}, session=session) collection_two.insert_one({"xyz": 999}, session=session) # Step 2: Start a client session. with client.start_session() as session: # Step 3: Use with_transaction to start a transaction, execute the callback, and commit (or abort on error). session.with_transaction(callback)
Este ejemplo resalta los componentes clave de la API de transacciones. En particular, utiliza la API de función de retorno. La API de función de retorno:
inicia una transacción
ejecuta las operaciones especificadas
confirma el resultado o finaliza la transacción en caso de error
Los errores en las operaciones del lado del servidor, como el DuplicateKeyError, pueden finalizar la transacción y producir un error de comando para alertar al usuario de que la transacción ha terminado. Este comportamiento es esperado y ocurre incluso si el cliente nunca llama a Session.abortTransaction(). Para incorporar una gestión personalizada de errores, se debe usar la Core API en la transacción.
La callback API incorpora lógica de reintento para ciertos errores. El controlador intenta volver a ejecutar la transacción después de un TransientTransactionError o un error de confirmación UnknownTransactionCommitResult.
A partir del MongoDB 6.2, el servidor no vuelve a intentar la transacción si recibe un error TransactionTooLargeForCache.
A partir de MongoDB 8.1, si una operación upsert se ejecuta en una transacción de múltiples documentos, entonces upsert no vuelve a intentarlo cuando encuentra un error de clave duplicada.
Importante
Utilice el controlador de MongoDB para su versión de MongoDB.
Al usar drivers, cada operación en la transacción debe pasar la sesión a cada operación.
Las operaciones en una transacción utilizan nivel de consistencia de lectura a nivel de transacción, nivel de confirmación de escritura a nivel de transacción y preferencia de lectura a nivel de transacción.
Puedes crear colecciones en transacciones de forma implícita o explícita. Consulta Crear colecciones e índices en una transacción.
# For a replica set, include the replica set name and a seedlist of the members in the URI string; e.g. # uriString = 'mongodb://mongodb0.example.com:27017,mongodb1.example.com:27017/?replicaSet=myRepl' # For a sharded cluster, connect to the mongos instances; e.g. # uri_string = 'mongodb://mongos0.example.com:27017,mongos1.example.com:27017/' client = Mongo::Client.new(uri_string, write_concern: {w: :majority, wtimeout: 1000}) # Prereq: Create collections. client.use('mydb1')['foo'].insert_one(abc: 0) client.use('mydb2')['bar'].insert_one(xyz: 0) # Step 1: Define the callback that specifies the sequence of operations to perform inside the transactions. callback = Proc.new do |my_session| collection_one = client.use('mydb1')['foo'] collection_two = client.use('mydb2')['bar'] # Important: You must pass the session to the operations. collection_one.insert_one({'abc': 1}, session: my_session) collection_two.insert_one({'xyz': 999}, session: my_session) end #. Step 2: Start a client session. session = client.start_session # Step 3: Use with_transaction to start a transaction, execute the callback, and commit (or abort on error). session.with_transaction( read_concern: {level: :local}, write_concern: {w: :majority, wtimeout: 1000}, read: {mode: :primary}, &callback)
Este ejemplo resalta los componentes clave de la API de transacciones. En particular, utiliza la API de función de retorno. La API de función de retorno:
inicia una transacción
ejecuta las operaciones especificadas
confirma el resultado o finaliza la transacción en caso de error
Los errores en las operaciones del lado del servidor, como el DuplicateKeyError, pueden finalizar la transacción y producir un error de comando para alertar al usuario de que la transacción ha terminado. Este comportamiento es esperado y ocurre incluso si el cliente nunca llama a Session.abortTransaction(). Para incorporar una gestión personalizada de errores, se debe usar la Core API en la transacción.
La callback API incorpora lógica de reintento para ciertos errores. El controlador intenta volver a ejecutar la transacción después de un TransientTransactionError o un error de confirmación UnknownTransactionCommitResult.
A partir del MongoDB 6.2, el servidor no vuelve a intentar la transacción si recibe un error TransactionTooLargeForCache.
A partir de MongoDB 8.1, si una operación upsert se ejecuta en una transacción de múltiples documentos, entonces upsert no vuelve a intentarlo cuando encuentra un error de clave duplicada.
Importante
Utilice el controlador de MongoDB para su versión de MongoDB.
Al usar drivers, cada operación en la transacción debe pasar la sesión a cada operación.
Las operaciones en una transacción utilizan nivel de consistencia de lectura a nivel de transacción, nivel de confirmación de escritura a nivel de transacción y preferencia de lectura a nivel de transacción.
Puedes crear colecciones en transacciones de forma implícita o explícita. Consulta Crear colecciones e índices en una transacción.
// Prereq: Create collections. CRUD operations in transactions must be on existing collections. client .database("mydb1") .collection::<Document>("foo") .insert_one(doc! { "abc": 0}) .await?; client .database("mydb2") .collection::<Document>("bar") .insert_one(doc! { "xyz": 0}) .await?; // Step 1: Define the callback that specifies the sequence of operations to perform inside the // transaction. async fn callback(session: &mut ClientSession) -> Result<()> { let collection_one = session .client() .database("mydb1") .collection::<Document>("foo"); let collection_two = session .client() .database("mydb2") .collection::<Document>("bar"); // Important: You must pass the session to the operations. collection_one .insert_one(doc! { "abc": 1 }) .session(&mut *session) .await?; collection_two .insert_one(doc! { "xyz": 999 }) .session(session) .await?; Ok(()) } // Step 2: Start a client session. let mut session = client.start_session().await?; // Step 3: Use and_run2 to start a transaction, execute the callback, and commit (or // abort on error). session.start_transaction().and_run2(callback).await?;
Este ejemplo utiliza la Core API. Dado que la Core API no incorpora lógica de reintentos para los errores de TransientTransactionError o UnknownTransactionCommitResult de confirmación, el ejemplo incluye lógica explícita para reintentar la transacción para estos errores:
Importante
Utilice el controlador de MongoDB para su versión de MongoDB.
Al usar drivers, cada operación en la transacción debe pasar la sesión a cada operación.
Las operaciones en una transacción utilizan nivel de consistencia de lectura a nivel de transacción, nivel de confirmación de escritura a nivel de transacción y preferencia de lectura a nivel de transacción.
Puedes crear colecciones en transacciones de forma implícita o explícita. Consulta Crear colecciones e índices en una transacción.
/* * Copyright 2008-present MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.mongodb.scala import org.mongodb.scala.model.{Filters, Updates} import org.mongodb.scala.result.UpdateResult import scala.concurrent.Await import scala.concurrent.duration.Duration //scalastyle:off magic.number class DocumentationTransactionsExampleSpec extends RequiresMongoDBISpec { // Implicit functions that execute the Observable and return the results val waitDuration = Duration(5, "seconds") implicit class ObservableExecutor[T](observable: Observable[T]) { def execute(): Seq[T] = Await.result(observable.toFuture(), waitDuration) } implicit class SingleObservableExecutor[T](observable: SingleObservable[T]) { def execute(): T = Await.result(observable.toFuture(), waitDuration) } // end implicit functions "The Scala driver" should "be able to commit a transaction" in withClient { client => assume(serverVersionAtLeast(List(4, 0, 0)) && !hasSingleHost()) client.getDatabase("hr").drop().execute() client.getDatabase("hr").createCollection("employees").execute() client.getDatabase("hr").createCollection("events").execute() updateEmployeeInfoWithRetry(client).execute() should equal(Completed()) client.getDatabase("hr").drop().execute() should equal(Completed()) } def updateEmployeeInfo(database: MongoDatabase, observable: SingleObservable[ClientSession]): SingleObservable[ClientSession] = { observable.map(clientSession => { val employeesCollection = database.getCollection("employees") val eventsCollection = database.getCollection("events") val transactionOptions = TransactionOptions.builder() .readPreference(ReadPreference.primary()) .readConcern(ReadConcern.SNAPSHOT) .writeConcern(WriteConcern.MAJORITY) .build() clientSession.startTransaction(transactionOptions) employeesCollection.updateOne(clientSession, Filters.eq("employee", 3), Updates.set("status", "Inactive")) .subscribe((res: UpdateResult) => println(res)) eventsCollection.insertOne(clientSession, Document("employee" -> 3, "status" -> Document("new" -> "Inactive", "old" -> "Active"))) .subscribe((res: Completed) => println(res)) clientSession }) } def commitAndRetry(observable: SingleObservable[Completed]): SingleObservable[Completed] = { observable.recoverWith({ case e: MongoException if e.hasErrorLabel(MongoException.UNKNOWN_TRANSACTION_COMMIT_RESULT_LABEL) => { println("UnknownTransactionCommitResult, retrying commit operation ...") commitAndRetry(observable) } case e: Exception => { println(s"Exception during commit ...: $e") throw e } }) } def runTransactionAndRetry(observable: SingleObservable[Completed]): SingleObservable[Completed] = { observable.recoverWith({ case e: MongoException if e.hasErrorLabel(MongoException.TRANSIENT_TRANSACTION_ERROR_LABEL) => { println("TransientTransactionError, aborting transaction and retrying ...") runTransactionAndRetry(observable) } }) } def updateEmployeeInfoWithRetry(client: MongoClient): SingleObservable[Completed] = { val database = client.getDatabase("hr") val updateEmployeeInfoObservable: Observable[ClientSession] = updateEmployeeInfo(database, client.startSession()) val commitTransactionObservable: SingleObservable[Completed] = updateEmployeeInfoObservable.flatMap(clientSession => clientSession.commitTransaction()) val commitAndRetryObservable: SingleObservable[Completed] = commitAndRetry(commitTransactionObservable) runTransactionAndRetry(commitAndRetryObservable) } }
Tip
Para un ejemplo en mongosh, consulta mongosh Ejemplo.
Transacciones y atomicidad
Para situaciones que requieren atomicidad de las lecturas y escrituras en varios documentos (en una sola colección o en varias), MongoDB admite transacciones distribuidas, incluidas las transacciones en sets de réplica y clústeres fragmentados.
Las transacciones distribuidas son atómicas:
Las transacciones aplican todos los cambios de datos o los revierten.
Si una transacción se confirma, todos los cambios de datos realizados en la transacción se guardan y son visibles fuera de la transacción.
Hasta que se produzca la confirmación de una transacción, los cambios de datos realizados en la transacción no son visibles fuera de la transacción.
Sin embargo, cuando una transacción se guarda en múltiples fragmentos, no todas las operaciones de lectura externas necesitan esperar a que el resultado de la transacción confirmada sea visible en todos los fragmentos. Por ejemplo, si se confirma una transacción y la escritura 1 es visible en el fragmento A, pero la escritura 2 aún no es visible en el fragmento B, una lectura externa con el nivel de consistencia de lectura
"local"puede leer los resultados de la escritura 1 sin ver la escritura 2.Cuando una transacción se aborta, todos los cambios de datos realizados en la transacción se descartan sin llegar a ser visibles. Por ejemplo, si alguna operación en la transacción falla, la transacción se aborta y todos los cambios de datos realizados en la transacción se descartan sin llegar a ser visibles.
Importante
En la mayoría de los casos, una transacción distribuida incurre en un costo de rendimiento mayor que las escrituras de documentos individuales, y la disponibilidad de transacciones distribuidas no debería ser un sustituto para un diseño de esquema efectivo. Para muchos casos, el modelo de datos desnormalizado (documento incrustado y matrices) seguirá siendo óptimo para tus datos y casos de uso. Es decir, en muchos casos, modelar tus datos de forma adecuada minimizará la necesidad de transacciones distribuidas.
Para consideraciones adicionales sobre el uso de transacciones (como el límite de tiempo de ejecución y el límite de tamaño del oplog), consulta también las consideraciones de producción.
Transacciones y operaciones
Las transacciones se pueden utilizar en múltiples operaciones, colecciones, bases de datos, documentos y fragmentos.
Para las transacciones:
Puedes crear colecciones e índices en transacciones. Para obtener más detalles, consulta Crear colecciones e índices en una transacción
Las colecciones utilizadas en una transacción pueden encontrarse en diferentes bases de datos.
Nota
No puedes crear nuevas colecciones en transacciones de escritura entre particiones. Por ejemplo, si guardas en una colección existente en una partición y creas implícitamente una colección en una partición diferente, MongoDB no puede realizar ambas operaciones en la misma transacción.
No se puede escribir en colecciones con tamaño fijo.
No puedes usar el nivel de consistencia de lectura
"snapshot"al leer de una colección con tamaño fijo. (A partir de MongoDB 5.0)No puedes leer ni escribir en colecciones en las bases de datos
config,adminolocal.No se puede escribir en las colecciones de
system.*.No puedes devolver el plan de query de las operaciones admitidas usando
explaino comandos similares.
Para los cursores creados fuera de una transacción, no puedes llamar a
getMoredentro de la transacción.Para los cursores creados en una transacción, no puedes llamar a
getMorefuera de la transacción.
No puedes especificar el comando
killCursorscomo la primera operación en una transacción.Además, si ejecutas el comando
killCursorsdentro de una transacción, el servidor detiene inmediatamente los cursores especificados. No espera la confirmación de la transacción.
Para obtener una lista de las operaciones no admitidas en las transacciones, consulta Operaciones restringidas.
Tip
Al crear o descartar una colección inmediatamente antes de iniciar una transacción, si se accede a la colección dentro de la transacción, realice la operación de creación o descarte con el nivel de confirmación de escritura "majority" para asegurarse de que la transacción pueda adquirir los bloqueos necesarios.
Crear colecciones e índices en una transacción
Puede realizar las siguientes operaciones en una transacción si no es una transacción de escritura entre fragmentos:
Crea colecciones.
Crea índices en nuevas colecciones vacías que se hayan creado anteriormente en la misma transacción.
Al crear una colección dentro de una transacción:
Se puede crear implícitamente una colección, como con:
una operación de inserción para una colección inexistente, o
una operación de actualizar/encontrar&modificar con
upsert: truepara una colección inexistente.
Puede crear explícitamente una colección utilizando el comando
createo su asistentedb.createCollection().
Cuando cree un índice dentro de una transacción [1], el índice que se va a crear debe estar en uno de los siguientes:
una colección inexistente. La colección se crea como parte de la operación.
una nueva colección vacía creada anteriormente en la misma transacción.
| [1] | También puede ejecutar db.collection.createIndex() y db.collection.createIndexes() en índices existentes para comprobar su existencia. Estas operaciones se completan con éxito sin crear el índice. |
Restricciones
No puedes crear nuevas colecciones en transacciones de escritura entre particiones. Por ejemplo, si guardas en una colección existente en una partición y creas implícitamente una colección en una partición diferente, MongoDB no puede realizar ambas operaciones en la misma transacción.
No se puede usar la etapa
$graphLookupdentro de una transacción durante el direccionamiento a una colección fragmentada.Para la creación explícita de una colección o un índice dentro de una transacción, el nivel de consistencia de lectura de la transacción debe ser
"local".Para crear explícitamente colecciones e índices, utiliza los siguientes comandos y métodos:
Operación de conteo
Para realizar una operación de conteo dentro de una transacción, utilice la etapa de agregación $count o la etapa de agregación $group (con una expresión $sum).
Los controladores de MongoDB proporcionan una API a nivel de colección countDocuments(filter, options) como un método asistente que utiliza el $group con una expresión $sum para realizar un conteo.
mongosh proporciona el método asistente db.collection.countDocuments() que utiliza $group con una expresión $sum para realizar un conteo.
Operación distinta
Para realizar una operación específica dentro de una transacción:
Para colecciones no fragmentadas, puedes utilizar el método
db.collection.distinct()o el comandodistinct, así como la canalización de agregación con la etapa$group.Para colecciones fragmentadas, no puede utilizar el método
db.collection.distinct()ni el comandodistinct.Para encontrar los valores distintos de una colección fragmentada, utilice la canalización de agregación con la etapa
$groupen su lugar. Por ejemplo:En lugar de
db.coll.distinct("x"), utilicedb.coll.aggregate([ { $group: { _id: null, distinctValues: { $addToSet: "$x" } } }, { $project: { _id: 0 } } ]) En lugar de
db.coll.distinct("x", { status: "A" }), utilice:db.coll.aggregate([ { $match: { status: "A" } }, { $group: { _id: null, distinctValues: { $addToSet: "$x" } } }, { $project: { _id: 0 } } ])
El pipeline devuelve un cursor a un documento:
{ "distinctValues" : [ 2, 3, 1 ] } Itere el cursor para acceder al documento de resultados.
Operaciones de información
Los comandos informativos, como hello, buildInfo, connectionStatus (y sus métodos asistentes) están permitidos en las transacciones; sin embargo, no pueden ser la primera operación de la transacción.
Operaciones restringidas
Las siguientes operaciones no están permitidas en las transacciones:
Creación de nuevas colecciones en transacciones de escritura entre particiones. Por ejemplo, si usted guarda en una colección existente en una partición y crea implícitamente una colección en una partición diferente, MongoDB no puede realizar ambas operaciones en la misma transacción.
Creación explícita de colecciones, como por ejemplo: Método
db.createCollection()e índices, por ejemplo: los métodosdb.collection.createIndexes()ydb.collection.createIndex(), cuando se utiliza un nivel de consistencia de lectura distinto de"local".Los comandos
listCollectionsylistIndexesy sus métodos asistentes.Otras operaciones que no son CRUD ni informativas, tales como
createUser,getParameter,count, etc. y sus asistentes.Operaciones paralelas. Para actualizar varios espacios de nombres simultáneamente, considera usar el comando
bulkWriteen cambio.
Transacciones y Sesiones
Las transacciones están asociadas a una sesión.
Puede tener como máximo una transacción abierta a la vez para una sesión.
Cuando se utilizan los drivers, cada operación en la transacción debe estar asociada a la sesión. Se debe consultar la documentación específica del driver para conseguir más detalles.
Si una sesión termina y tiene una transacción abierta, la transacción se abortará.
Nivel de consistencia de lectura/nivel de confirmación de escritura/preferencia de lectura
Transacciones y preferencia de lectura
Las operaciones en una transacción utilizan la preferencia de lectura a nivel de transacción.
Usando los drivers, se puede establecer la preferencia de lectura a nivel de transacción al inicio de la transacción:
Si la preferencia de lectura a nivel de transacción no está establecida, la transacción utiliza la preferencia de lectura a nivel de sesión.
Si la preferencia de lectura a nivel de transacción y la de nivel de sesión no están establecidas, la transacción utiliza la preferencia de lectura a nivel de cliente. Por defecto, la preferencia de lectura a nivel de cliente es
primary.
Las transacciones que contienen operaciones de lectura deben usar la preferencia de primary lectura. Todas las operaciones de una transacción deben dirigirse al mismo miembro.
Transacciones y nivel de consistencia de lectura
Las operaciones en una transacción utilizan el nivel de consistencia de lectura de la transacción. Esto significa que un nivel de consistencia de lectura establecido a nivel de colección y base de datos se ignora dentro de la transacción.
Puede establecer el nivel de consistencia de lectura a nivel de transacción al inicio de la transacción.
Si el nivel de consistencia de lectura a nivel de transacción no está establecido, el nivel de consistencia de lectura a nivel de transacción por defecto se ajusta al nivel de consistencia de lectura a nivel de sesión.
Si el nivel de consistencia de lectura de transacción y el de sesión no están configurados, el nivel de consistencia de lectura de transacción por defecto es el nivel de consistencia de lectura de cliente. Por defecto, el nivel de consistencia de lectura de es
"local"para las lecturas en el primario. Véase también:
Las transacciones soportan los siguientes niveles de consistencia de lectura:
"local"
El nivel de consistencia de lectura
"local"devuelve los datos más recientes disponibles del nodo, pero puede ser revertido.En un set de réplicas, incluso si una transacción utiliza un nivel de consistencia de lectura de
local, es posible que observe un aislamiento de lectura más fuerte, donde la operación lee desde un snapshot en el punto en el que se abrió la transacción.Para las transacciones en un clúster, el nivel de consistencia de lectura
"local"no puede garantizar que los datos provengan de la misma vista de snapshot en todos los fragmentos. Si se requiere el aislamiento de snapshot, utiliza un"snapshot"nivel de consistencia de lectura.Puedes crear colecciones e índices dentro de una transacción. Si creas explícitamente una colección o un índice, la transacción debe usar el nivel de consistencia de lectura
"local". Si creas implícitamente una colección, puedes utilizar cualquiera de los niveles de consistencia de lectura disponibles para las transacciones.
"majority"
Si la transacción se confirma con el nivel de confirmación de escritura "mayoría", el nivel de consistencia de lectura
"majority"devuelve datos que hayan sido reconocidos por la mayoría de los miembros del set de réplicas y no se pueden revertir. De lo contrario, el nivel de consistencia de lectura"majority"no ofrece garantías de que las operaciones de lectura accedan a datos comprometidos por la mayoría.Para las transacciones en un clúster fragmentado, el nivel de consistencia de lectura
"majority"no puede garantizar que los datos provengan de la misma vista de snapshot en todos los fragmentos. Si se requiere el aislamiento de snapshot, utiliza el nivel de consistencia de lectura"snapshot".
"snapshot"
El nivel de consistencia de lectura
"snapshot"devuelve datos de un snapshot de los datos comprometidos por mayoría si la transacción se realiza con la confirmación del nivel de confirmación de escritura "mayoría".Si la transacción no utiliza nivel de confirmación de escritura "mayoría" para la confirmación, el
"snapshot"nivel de consistencia de lectura no garantiza que las operaciones de lectura hayan utilizado un snapshot de los datos confirmados por la mayoría.Para las transacciones en clústeres fragmentados, la
"snapshot"vista de los datos se sincroniza a través de los fragmentos.
Transacciones y nivel de confirmación de escritura
Las transacciones utilizan el nivel de confirmación de escritura a nivel de transacción para confirmar las operaciones de escritura. Las operaciones de escritura dentro de las transacciones deben ejecutarse sin una especificación explícita de nivel de confirmación de escritura y utilizar el nivel de confirmación de escritura por defecto. En el momento de la confirmación, las escrituras se confirmaron utilizando el nivel de confirmación de escritura a nivel de transacción.
Tip
No establezca explícitamente el nivel de confirmación de escritura para las operaciones de escritura individuales dentro de una transacción. Configurar niveles de confirmación de escritura para las operaciones de escritura individuales dentro de una transacción genera un error.
Puede establecer el nivel de confirmación de escritura a nivel de transacción al inicio de la transacción:
Si el nivel de confirmación de escritura a nivel de transacción no está establecido, se utiliza por defecto el nivel de confirmación de escritura a nivel de sesión para la confirmación.
Si el nivel de confirmación de escritura a nivel de transacción y el nivel de confirmación de escritura a nivel de sesión no están configurados, el nivel de confirmación de escritura a nivel de transacción por defecto es el nivel de confirmación de escritura a nivel de cliente de:
w: "majority"en MongoDB 5.0 y posteriores, con diferencias para implementaciones que contienen árbitros. Consulte nivel de confirmación de escritura implícito por defecto.
Las transacciones tienen soporte para todos los valores de w de nivel de confirmación de escritura, incluidos:
w: 1
El nivel de confirmación de escritura
w: 1devuelve un reconocimiento después de que la confirmación se haya aplicado al primario.Importante
Cuando se realiza una confirmación
w: 1, la transacción puede revertirse si hay una conmutación por error.Cuando confirma el nivel de confirmación de escritura
w: 1, el nivel de consistencia de lectura a nivel de transacción"majority"no ofrece garantías de que las operaciones de lectura en la transacción lean datos confirmados por la mayoría.Cuando se confirma el nivel de confirmación de escritura
w: 1, el nivel de consistencia de lectura a nivel de transacción"snapshot"no proporciona garantías de que las operaciones de lectura en la transacción hayan utilizado una snapshot de los datos confirmados por la mayoría.
w: "majority"
El nivel de confirmación de escritura
w: "majority"devuelve un reconocimiento después de que la confirmación se haya aplicado a la mayoría de los miembros con derecho a voto.Cuando se confirma el nivel de confirmación de escritura
w: "majority", el nivel de consistencia de lectura a nivel de transacción"majority"garantiza que las operaciones hayan leído datos confirmados por la mayoría. Para las transacciones en clústeres particionados, esta vista de los datos confirmados por la mayoría no se sincroniza entre los fragmentos.Cuando se confirma el nivel de confirmación de escritura
w: "majority", el nivel de consistencia de lectura a nivel de transacción"snapshot"ofrece garantías de que las operaciones han leído de una snapshot sincronizada de datos confirmados por la mayoría.
Nota
Independientemente del nivel de confirmación de escritura especificado para la transacción, la operación de confirmación para una transacción de clúster incluye algunas partes que utilizan el nivel de confirmación de escritura {w:
"majority", j: true}.
El parámetro del servidor coordinateCommitReturnImmediatelyAfterPersistingDecision controla cuándo se devuelven las decisiones de confirmación de transacción al cliente.
El parámetro fue introducido en MongoDB 5.0 con un valor por defecto de true. En MongoDB 6.1, el valor por defecto cambia a false.
Cuando coordinateCommitReturnImmediatelyAfterPersistingDecision falsees, el coordinador de transacciones de fragmentos espera a que todos los miembros reconozcan una confirmación de transacción antes de devolver la decisión de confirmación al cliente.
Si especifica una preocupación de escritura para las "majority" escrituras y la operación no se replica a la mayoría calculada de los miembros del conjunto de réplicas antes de devolver una respuesta, los datos se replicarán o se revertirán.wtimeout Consulte.
Independientemente del nivel de confirmación de escritura especificado para la transacción, el controlador aplica w: "majority" como nivel de confirmación de escritura al volver a intentar commitTransaction.
Información general
Las siguientes secciones describen más consideraciones para las transacciones.
Consideraciones de Producción
Para transacciones en entornos de producción, consulte Consideraciones de producción. Además, para clústeres fragmentados, consulte Consideraciones de producción (Clústeres fragmentados).
Árbitros
No puedes cambiar una clave de fragmentación mediante una transacción si el set de réplicas tiene un árbitro. Los árbitros no pueden participar en las operaciones de datos requeridas para las transacciones de múltiples fragmentos.
Las transacciones cuyas operaciones de escritura abarcan varios fragmentos generarán un error y se abortarán si alguna operación de transacción lee o escribe en una partición que contiene un árbitro.
Restricción de configuración de fragmentos
No puedes ejecutar transacciones en un clúster que tenga una partición con writeConcernMajorityJournalDefault configurado en false (como una partición con un nodo votante que utiliza el motor de almacenamiento en memoria).
Nota
Independientemente del nivel de confirmación de escritura especificado para la transacción, la operación de confirmación para una transacción de clúster incluye algunas partes que utilizan el nivel de confirmación de escritura {w:
"majority", j: true}.
Diagnósticos
Para obtener el estado de la transacción y las métricas, utilice los siguientes métodos:
Origen | Devuelve |
|---|---|
db.serverStatus() methodserverStatus command | Devuelve las métricas de transacciones. Algunos campos de respuesta |
| Devuelve:
|
db.currentOp() methodcurrentOp command | Devuelve:
|
Incluye información sobre las transacciones lentas (que son transacciones que superan el umbral de |
Compatibilidad de características entre versiones (FCV)
Para utilizar transacciones, la featureCompatibilityVersion de todos los miembros de la implementación debe ser al menos:
Implementación | Mínimo featureCompatibilityVersion |
|---|---|
Set de réplicas |
|
Clúster fragmentado |
|
Para comprobar la compatibilidad de características entre versiones de un nodo, conéctese al nodo y ejecute el siguiente comando:
db.adminCommand( { getParameter: 1, featureCompatibilityVersion: 1 } )
Para obtener más información, consulte la página de referencia setFeatureCompatibilityVersion.
Motores de almacenamiento
Las transacciones se admiten en conjuntos de réplicas y clústeres fragmentados donde:
el primario utiliza el motor de almacenamiento WiredTiger, y
los miembros secundarios utilizan el motor de almacenamiento WiredTiger o los motores de almacenamiento en memoria.
Nota
No puedes ejecutar transacciones en un clúster que tiene una partición con writeConcernMajorityJournalDefault configurada en false, como una partición con un nodo votante que utiliza el motor de almacenamiento en memoria.
Limite el tiempo de espera de la sección crítica
A partir de MongoDB 5.2 (y 5.0.4):
Cuando una query accede a un fragmento, una migración de fragmento o una operación DDL puede retener la sección crítica de la colección.
Para limitar el tiempo que un fragmento espera por una sección crítica dentro de una transacción, utilice el parámetro
metadataRefreshInTransactionMaxWaitMS.Nota
A partir de MongoDB 8.1, el parámetro antiguo
metadataRefreshInTransactionMaxWaitBehindCritSecMSse renombra ametadataRefreshInTransactionMaxWaitMS. Puedes continuar usandometadataRefreshInTransactionMaxWaitBehindCritSecMScomo nombre de parámetro, pero está obsoleto y se eliminará en una versión futura de MongoDB.