Overview
En esta guía, puede aprender cómo usar el driver de Node.js para realizar transacciones. Las transacciones permiten ejecutar una serie de operaciones que no alteran ningún dato hasta que toda la transacción esté comprometida. Si alguna operación de la transacción falla, el controlador finaliza la transacción y descarta cualquier cambio en los datos antes de que se hagan visibles. Esta funcionalidad se llama atomicidad.
Como todas las operaciones de guardar en un solo documento en MongoDB son atómicas, es posible que desee utilizar transacciones para realizar un cambio atómico que modifique varios documentos. Esta situación requiere una transacción multi-documento. Las transacciones multi-documento son ACID compliant porque MongoDB garantiza que los datos involucrados en tus operaciones de transacción se mantengan coherentes, incluso si el driver encuentra errores inesperados.
Para obtener más información sobre el cumplimiento de ACID y las transacciones, consulte nuestra artículo sobre transacciones ACID.
Nota
Para ejecutar una transacción multi-documento, debes estar conectado a una implementación que ejecute MongoDB Server versión 4.0 o posterior.
Para obtener una lista detallada de limitaciones, consulta la sección Transacciones y operaciones en el manual de servidor.
Aprende más sobre cómo usar el driver para realizar transacciones multi-documento en las siguientes secciones de esta guía:
Coherencia causal
MongoDB habilita la coherencia causal en ciertas sesiones de clientes. El modelo de coherencia causal garantiza que en un sistema distribuido, las operaciones dentro de una sesión se ejecuten en un orden causal. Los clientes observan resultados que son coherentes con las relaciones causales, o las dependencias entre las operaciones. Por ejemplo, si realizas una serie de operaciones donde una depende lógicamente del resultado de otra, las lecturas subsecuentes reflejarán esa relación de dependencia.
Para garantizar la coherencia causal, las sesiones de los clientes deben cumplir los siguientes requisitos:
Al iniciar una sesión, el controlador debe habilitar la opción de consistencia causal. Esta opción está habilitada por defecto.
Las operaciones deben ejecutarse en una sola sesión en un solo hilo. De lo contrario, las sesiones o hilos deben comunicarse entre sí los valores de operation time y tiempo de clúster. Para ver un ejemplo de dos sesiones que comunican estos valores, consulte los Ejemplos de coherencia causal en el manual del servidor de MongoDB.
Debes utilizar un
majoritynivel de consistencia de lectura.Debe usar un
majoritynivel de confirmación de escritura (write concern). Este es el valor predeterminado de nivel de confirmación de escritura (write concern).
La siguiente tabla describe las garantías que brindan las sesiones causalmente consistentes:
garantías | Descripción |
|---|---|
Leer las escrituras | Las operaciones de lectura reflejan los resultados de las operaciones de escritura anteriores. |
Lecturas monotónicas | Las operaciones de lectura no devuelven resultados que reflejen un estado de datos anterior al de una operación de lectura previa. |
Escrituras monotónicas | Si una operación de escritura debe preceder a otras operaciones de escritura, el servidor ejecuta esta operación de escritura primero. Por ejemplo, si llama a |
Las escrituras siguen a las lecturas | Si una operación de escritura debe seguir a otras operaciones de lectura, el servidor primero ejecuta las operaciones de lectura. Por ejemplo, si llamas a |
Tip
Para aprender más sobre los conceptos mencionados en esta sección, consulta las siguientes entradas del manual del servidor MongoDB:
API de transacciones
El controlador proporciona dos API para realizar transacciones: la API principal y la API de transacciones convenientes.
La Core API es un framework que te permite crear, confirmar y finalizar transacciones. Al utilizar esta API, debe realizar explícitamente las siguientes acciones:
Crea, confirma y finaliza la transacción.
Cree y finalice la sesión en la que se ejecute la transacción.
Implementar lógica de manejo de errores.
La API de transacciones conveniente es un marco que te permite realizar transacciones sin ser responsable de comprometerlas o finalizarlas. Esta API incorpora automáticamente lógica de manejo de errores para reintentar operaciones cuando el servidor muestra ciertos tipos de errores. Para obtener más información sobre este comportamiento, consulta la sección Errores de transacción de esta guía.
Importante
Cuando se conecta a MongoDB Server versión 4.2 o anterior, solo puede realizar operaciones de escritura en una transacción en colecciones que ya existen. Cuando se conecta a MongoDB Server versión 4.4 y posteriores, el servidor crea automáticamente colecciones según sea necesario cuando realiza operaciones de escritura en una transacción. Para obtener más información sobre este comportamiento, consulte Crear colecciones e índices en una transacción en el manual del servidor.
Core API
La API central proporciona los siguientes métodos para implementar transacciones:
startSession(): crea una nueva instancia de
ClientSessionstartTransaction(): inicia una nueva transacción
commitTransaction(): confirma la transacción activa en la sesión en la que fue creada
abortTransaction(): finaliza la transacción activa en la sesión en la que fue creada.
endSession(): finaliza la sesión activa
Debes realizar los siguientes pasos cuando uses esta API:
Pasa la instancia de la sesión a cada operación que desees ejecutar en esa sesión.
Implemente un bloque
catchen el que identifique los errores de transacción del servidor y la lógica de control de errores implementada.
El siguiente código demuestra cómo realizar una transacción utilizando la Core API:
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
Utilizar una sesión con el cliente que la inició
El controlador lanza un error si se proporciona una sesión de una instancia MongoClient a una instancia de cliente diferente.
Por ejemplo, el siguiente código genera un error MongoInvalidArgumentError porque crea una instancia ClientSession desde el cliente client1, pero proporciona esta sesión al cliente client2 para una operación de escritura:
const session = client1.startSession(); client2.db('myDB').collection('myColl').insertOne({ name: 'Jane Eyre' }, { session });
Tip
Gestión explícita de recursos
El controlador de Nodo.js admite de forma nativa la gestión explícita de recursos para MongoClient, ClientSession, ChangeStreams y cursores. Esta característica es experimental y está sujeta a cambios. Para aprender a utilizar la gestión explícita de recursos, consulta las Notas de versión v6.9.
Para ver un ejemplo completamente ejecutable que utiliza esta API, consulte Utilice el ejemplo de usode la API principal.
API de transacciones convenientes
La API de Transacciones Convenientes ofrece los siguientes métodos para implementar transacciones:
withSession(): ejecuta la función de retorno que recibe dentro de una sesión. La API gestiona automáticamente la creación y finalización de la sesión.
withTransaction(): ejecuta la devolución de llamada que se le pasa dentro de una transacción y llama al
commitTransaction()método cuando la devolución de llamada regresa.
Estos métodos devuelven el valor que devuelve la devolución de llamada. Por ejemplo, si una devolución de llamada que se pasa al método withTransaction() devuelve el documento { hello: "world" }, el método withTransaction() también lo devuelve.
Importante
Para evitar errores de bucle infinito, asegúrese de que la función de retorno que pase al método withTransaction() capture cualquier error que genere.
Cuando uses la API de Transacciones Convenientes, puedes propagar valores de retorno desde la función de retorno como los valores de retorno de los métodos withTransaction() y withSession() para trabajar con ellos en otras partes de tu código.
Debes realizar los siguientes pasos cuando uses esta API:
Pasa la instancia de la sesión a cada operación que desees ejecutar en esa sesión.
Implemente la sintaxis async
awaitpara cada operación en la sesión.Evitar el paralelismo, como llamar al método
Promise.all(). Utilizar sesiones en paralelo suele conducir a errores en el servidor.
El siguiente código demuestra cómo realizar una transacción utilizando la API de Transacciones Convenientes:
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 un ejemplo completamente ejecutable que utiliza esta API, consulte el ejemplo de uso de la API de transacciones convenientes.
Nota
Operaciones paralelas no admitidas
El driver de nodo.js no admite la ejecución de operaciones en paralelo dentro de una única transacción.
Opciones de transacción
Puedes pasar una instancia TransactionOptions a los métodos startTransaction() y withTransaction() para configurar cómo ejecuta el driver una transacción. Cuando especifica una opción, sustituye el valor de la opción que podría haber configurado en su instancia de MongoClient.
La siguiente tabla incluye opciones que se pueden especificar en una instancia de TransactionOptions:
Configuración | Descripción |
|---|---|
| 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 la duración que puede ejecutar la acción de commit en una transacción, en milisegundos. |
Para obtener una lista completa de opciones, consulte la documentación de la API de TransactionOptions.
Nota
La transacción hereda los ajustes de tu instancia de MongoClient a menos que los especifica en las opciones de la transacción.
El siguiente código muestra cómo definir y pasar opciones de transacción al método startTransaction():
const txnOpts = { readPreference: 'primary', readConcern: { level: 'local' }, writeConcern: { w: 'majority' }, maxCommitTimeMS: 1000 }; session.startTransaction(txnOpts);
Errores de transacción
Debido a que las transacciones de MongoDB son compatibles con ACID, el driver podría producir errores durante la operación para garantizar que tus datos se mantengan coherentes. Si ocurren los siguientes errores, tu aplicación debe volver a intentar la transacción:
TransientTransactionError:: Se produce si una operación de escritura encuentra un error antes de que el controlador confirme la transacción. Para obtener más información sobre este tipo de error, consulte la descripción de TransientTransactionError en la página de la API de controladores en el manual del servidor.UnknownTransactionCommitResult: Se lanza si la operación de confirmación encuentra un error. Para obtener más información sobre este tipo de error, consulta la descripción UnknownTransactionCommitResult en la página de controladores de la API en el manual del servidor.
Las siguientes secciones describen cómo gestionar estos errores al utilizar diferentes APIs.
Manejo conveniente de errores de API de transacciones
La API de transacciones convenientes incorpora lógica de reintento para estos tipos de errores. El controlador reintenta automáticamente la transacción hasta que se produzca una confirmación exitosa.
Manejo de errores de Core API
Si está usando la Core API para realizar una transacción, debe añadir las siguientes funciones de gestión de errores a su aplicación:
Una función que vuelve a intentar toda la transacción cuando el conductor encuentra un
TransientTransactionErrorUna función que reintenta la operación de confirmación cuando el controlador encuentra un
UnknownTransactionCommitResult
Estas funciones deben ejecutarse hasta que se realice un compromiso exitoso o se produzca un error diferente. Para un ejemplo de esta lógica de reintentos, consulta la sección de la Core API en la página de la API de controladores del manual del servidor.