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.
Dado que todas las operaciones de escritura en un solo documento en MongoDB son atómicas, podría ser útil usar transacciones para realizar un cambio atómico que modifique varios documentos. Esta situación requiere una transacción multidocumento. Las transacciones multidocumento cumplen con ACID porque MongoDB garantiza que los datos involucrados en las operaciones de transacción se mantengan consistentes, incluso si el controlador encuentra errores inesperados.
Para obtener más información sobre el cumplimiento y las transacciones de ACID, consulte nuestra Artículo sobre transacciones ACID.
Nota
Para ejecutar una transacción de múltiples documentos, debe 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 permite la consistencia causal en ciertas sesiones de cliente. El modelo de consistencia causal garantiza que, en un sistema distribuido, las operaciones dentro de una sesión se ejecuten en un orden causal. Los clientes observan resultados consistentes con las relaciones causales o las dependencias entre operaciones. Por ejemplo, si se realiza una serie de operaciones donde una depende lógicamente del resultado de otra, las lecturas posteriores reflejan la 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 subproceso. De lo contrario, las sesiones o subprocesos deben comunicarse entre sí los valores de tiempo de la operación y del clúster. Para ver un ejemplo de dos sesiones que comunican estos valores, consulte los ejemplos de consistencia causal en el manual de MongoDB Server.
Debes utilizar un
majorityleer preocupación.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ía | 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 anterior. |
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 ejecuta primero las operaciones de lectura. Por ejemplo, si llama a |
Tip
Para obtener más información sobre los conceptos mencionados en esta sección, consulte las siguientes entradas del manual de MongoDB Server:
API de transacciones
El controlador proporciona dos API para realizar transacciones: la API principal y la API de transacciones convenientes.
La API principal es un marco que permite crear, confirmar y finalizar transacciones. Al usar esta API, debe realizar explícitamente las siguientes acciones:
Crear, confirmar y finalizar la transacción.
Crea y finaliza la sesión en la que ejecutas la transacción.
Implementar lógica de manejo de errores.
La API de Transacciones Convenientes es un marco que permite realizar transacciones sin tener que confirmarlas ni finalizarlas. Esta API incorpora automáticamente lógica de gestión de errores para reintentar operaciones cuando el servidor genera ciertos tipos de error. Para obtener más información sobre este comportamiento, consulte la sección "Errores de Transacción" de esta guía.
Importante
Al conectarse a MongoDB Server (versión 4.2 o anterior), solo se pueden realizar operaciones de escritura en una transacción en colecciones ya existentes. Al conectarse a MongoDB Server (versión o 4.4 posterior), el servidor crea automáticamente colecciones según sea necesario al realizar 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 principal proporciona los siguientes métodos para implementar transacciones:
startSession(): crea una nueva
ClientSessioninstanciastartTransaction(): 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 al utilizar esta API:
Pase la instancia de sesión a cada operación que desee ejecutar en esa sesión.
Implemente un bloque
catchen el que identifique errores de transacciones del servidor e implemente la lógica de manejo de errores.
El siguiente código demuestra cómo realizar una transacción utilizando la API principal:
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
Utilice 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 proporciona los siguientes métodos para implementar transacciones:
withSession(): ejecuta la devolución de llamada que se le pasa dentro de una sesión. La API gestiona la creación y finalización de la sesión automáticamente.
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 devolución de llamada que pase al método withTransaction() detecte cualquier error que genere.
Cuando utiliza la API de transacciones convenientes, puede propagar valores de retorno de la devolución de llamada como valores de retorno de los métodos withTransaction() y withSession() para trabajar con ellos en otras partes de su código.
Debes realizar los siguientes pasos al utilizar esta API:
Pase la instancia de sesión a cada operación que desee ejecutar en esa sesión.
Implemente la sintaxis async
awaitpara cada operación en la sesión.Evite el paralelismo, como llamar al método
Promise.all(). Usar sesiones en paralelo suele provocar errores del servidor.
El siguiente código demuestra cómo realizar una transacción mediante 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
Puede pasar una instancia TransactionOptions a los métodos startTransaction() y withTransaction() para configurar cómo el controlador realiza una transacción. Al especificar una opción, esta anula el valor de la opción que haya configurado en su instancia MongoClient.
La siguiente tabla incluye opciones que puede especificar en una instancia 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 el tiempo que puede ejecutarse una acción de confirmación 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 las configuraciones de su instancia MongoClient a menos que las especifique en sus opciones de 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
Dado que las transacciones de MongoDB cumplen con ACID, el controlador podría generar errores durante la operación para garantizar la coherencia de los datos. Si se producen los siguientes errores, la aplicación debe reintentar la transacción:
TransientTransactionError: Se genera 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 del manual del servidor.UnknownTransactionCommitResult: Se genera si la operación de confirmación detecta un error. Para obtener más información sobre este tipo de error, consulte la descripción de UnknownTransactionCommitResult en la página de la API de controladores del manual del servidor.
Las siguientes secciones describen cómo manejar estos errores al utilizar diferentes API.
Manejo conveniente de errores de API de transacciones
La API de Transacciones Convenientes incorpora lógica de reintento para estos tipos de error. El controlador reintenta automáticamente la transacción hasta que se confirma correctamente.
Manejo de errores de la API principal
Si está utilizando la API principal para realizar una transacción, debe agregar las siguientes funciones de manejo 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 vuelve a intentar la operación de confirmación cuando el controlador encuentra un
UnknownTransactionCommitResult
Estas funciones deben ejecutarse hasta que se confirme correctamente o se produzca un error diferente. Para ver un ejemplo de esta lógica de reintento, consulte la sección API principal en la página API de controladores del manual del servidor.