Come aggirare la mancanza di transazioni in MongoDB?


139

So che ci sono domande simili qui, ma mi stanno dicendo di tornare ai normali sistemi RDBMS se ho bisogno di transazioni o uso operazioni atomiche o commit a due fasi . La seconda soluzione sembra la scelta migliore. Il terzo che non desidero seguire perché sembra che molte cose potrebbero andare storte e non posso provarlo in tutti gli aspetti. Sto facendo fatica a riformattare il mio progetto per eseguire operazioni atomiche. Non so se questo provenga dal mio punto di vista limitato (finora ho lavorato solo con i database SQL) o se in realtà non è possibile farlo.

Vorremmo testare MongoDB presso la nostra azienda. Abbiamo scelto un progetto relativamente semplice: un gateway SMS. Consente al nostro software di inviare messaggi SMS alla rete cellulare e il gateway fa il lavoro sporco: in realtà comunica con i provider tramite diversi protocolli di comunicazione. Il gateway gestisce anche la fatturazione dei messaggi. Ogni cliente che richiede il servizio deve acquistare alcuni crediti. Il sistema riduce automaticamente il saldo dell'utente quando viene inviato un messaggio e nega l'accesso se il saldo è insufficiente. Anche perché siamo clienti di fornitori di SMS di terze parti, potremmo anche avere i nostri saldi con loro. Dobbiamo tenere traccia anche di quelli.

Ho iniziato a pensare a come posso archiviare i dati richiesti con MongoDB se riduco la complessità (fatturazione esterna, invio di SMS in coda). Provenendo dal mondo SQL, vorrei creare una tabella separata per gli utenti, un'altra per i messaggi SMS e una per la memorizzazione delle transazioni relative al saldo degli utenti. Diciamo che creo raccolte separate per tutti quelli in MongoDB.

Immagina un'attività di invio di SMS con i seguenti passaggi in questo sistema semplificato:

  1. controlla se l'utente ha un equilibrio sufficiente; negare l'accesso se non c'è credito sufficiente

  2. inviare e archiviare il messaggio nella raccolta SMS con i dettagli e i costi (nel sistema live il messaggio avrebbe un statusattributo e un'attività lo prenderebbe per la consegna e fisserebbe il prezzo dell'SMS in base al suo stato attuale)

  3. ridurre il saldo degli utenti in base al costo del messaggio inviato

  4. registra la transazione nella raccolta delle transazioni

Ora qual è il problema con quello? MongoDB può eseguire aggiornamenti atomici su un solo documento. Nel flusso precedente potrebbe accadere che si verifichi un qualche tipo di errore e il messaggio venga archiviato nel database ma il saldo dell'utente non viene aggiornato e / o la transazione non viene registrata.

Ho avuto due idee:

  • Crea una singola raccolta per gli utenti e archivia il saldo come campo, transazioni e messaggi relativi all'utente come documenti secondari nel documento dell'utente. Poiché siamo in grado di aggiornare i documenti atomicamente, questo risolve effettivamente il problema di transazione. Svantaggi: se l'utente invia molti messaggi SMS, la dimensione del documento potrebbe aumentare e il limite del documento di 4 MB potrebbe essere raggiunto. Forse posso creare documenti storici in tali scenari, ma non penso che sarebbe una buona idea. Inoltre, non so quanto veloce sarebbe il sistema se invii sempre più dati allo stesso grande documento.

  • Crea una raccolta per gli utenti e una per le transazioni. Esistono due tipi di transazioni: acquisto di credito con cambio saldo positivo e messaggi inviati con cambio saldo negativo. La transazione può avere un documento secondario; ad esempio nei messaggi inviati i dettagli dell'SMS possono essere incorporati nella transazione. Svantaggi: non memorizzo il saldo utente corrente, quindi devo calcolarlo ogni volta che un utente tenta di inviare un messaggio per dire se il messaggio potrebbe passare o meno. Temo che questo calcolo possa rallentare con l'aumentare del numero di transazioni archiviate.

Sono un po 'confuso su quale metodo scegliere. Ci sono altre soluzioni? Non sono riuscito a trovare online le migliori pratiche su come aggirare questo tipo di problemi. Immagino che molti programmatori che stanno cercando di acquisire familiarità con il mondo NoSQL affrontino problemi simili all'inizio.


61
Scusami se sbaglio, ma sembra che questo progetto userà un archivio di dati NoSQL indipendentemente dal fatto che ne trarrà beneficio o meno. NoSQL non è un'alternativa a SQL come scelta "fashion" ma per quando la tecnologia dei RDBMS relazionali non si adatta allo spazio problematico e un archivio dati non relazionale. Molte delle tue domande hanno "Se fosse SQL allora ..." e questo mi suona un campanello d'allarme. Tutti i NoSQL sono nati dall'esigenza di risolvere un problema che SQL non poteva e quindi sono stati in qualche modo generalizzati per rendere più facile l'uso e quindi, naturalmente, il carrozzone inizia a rotolare.
PurplePilot,

4
Sono consapevole che questo progetto non è esattamente il migliore per provare NoSQL. Tuttavia ho paura se iniziamo a usarlo con altri progetti (diciamo un software di gestione delle raccolte di biblioteche perché siamo nella gestione delle raccolte) e improvvisamente arriva una sorta di richiesta che richiede transazioni (ed è effettivamente lì, immagina che un libro viene trasferito da una raccolta all'altra) dobbiamo sapere come possiamo superare il problema. Forse sono solo io ad avere una mentalità ristretta e pensare che ci sia sempre bisogno di transazioni. Ma potrebbe esserci un modo per superare questi in qualche modo.
NagyI,

3
Sono d'accordo con PurplePilot, dovresti scegliere una tecnologia che si adatta a una soluzione, non cercare di innestare una soluzione che non è appropriata per un problema. La modellazione dei dati per i database dei grafi è un paradigma completamente diverso rispetto alla progettazione RDBMS e devi dimenticare tutto ciò che conosci e riapprendere il nuovo modo di pensare.

9
Capisco che dovrei usare lo strumento appropriato per l'attività. Tuttavia per me - quando leggo risposte come questa - sembra che NoSQL non sia adatto a nulla in cui i dati sono critici. È buono per Facebook o Twitter dove se alcuni commenti si perdono il mondo continua, ma tutto ciò che è sopra è fuori mercato. Se questo è vero, non capisco perché gli altri si preoccupano di costruire ad es. un webstore con MongoDB: kylebanker.com/blog/2010/04/30/mongodb-and-ecommerce Indica persino che la maggior parte delle transazioni può essere superata con operazioni atomiche. Quello che sto cercando è il come.
NagyI,

2
Dici che "sembra che NoSQL non sia buono per nulla in cui i dati sono critici" non è vero dove non è buono (forse) è l'elaborazione transazionale del tipo ACID transazionale. Inoltre, NoSQL è progettato per archivi di dati distribuiti che gli archivi di tipo SQL possono essere molto difficili da raggiungere quando si entra negli scenari di replica dello slave principale. NoSQL ha strategie per l'eventuale coerenza e garantisce che venga utilizzato solo l'ultimo set di dati ma non ACID.
PurplePilot,

Risposte:


23

A partire da 4.0, MongoDB avrà transazioni ACID multi-documento. Il piano è di abilitare prima quelli nelle distribuzioni dei set di repliche, seguiti dai cluster frammentati. Le transazioni in MongoDB si sentiranno proprio come le transazioni con cui gli sviluppatori hanno familiarità con i database relazionali: saranno multiistruzione, con semantica e sintassi simili (come start_transactione commit_transaction). È importante sottolineare che le modifiche a MongoDB che abilitano le transazioni non influiscono sulle prestazioni dei carichi di lavoro che non le richiedono.

Per maggiori dettagli vedi qui .

Avere transazioni distribuite, non significa che dovresti modellare i tuoi dati come in database relazionali tabulari. Abbraccia la potenza del modello di documento e segui le buone e consigliate pratiche di modellazione dei dati.


1
Le transazioni sono arrivate! 4.0 GAed. mongodb.com/blog/post/…
Grigori Melnik,

Le transazioni MongoDB hanno ancora delle limitazioni sulla dimensione della transazione 16 MB, recentemente ho avuto un caso d'uso in cui ho bisogno di mettere 50k record da un file in mongoDB, quindi per mantenere la proprietà atomica ho pensato di usare le transazioni ma da 50k json records superare questo limite, genera l'errore "La dimensione totale di tutte le operazioni di transazione deve essere inferiore a 16793600. La dimensione effettiva è 16793817". per maggiori dettagli è possibile consultare il biglietto ufficiale Jira aperto su mongoDB jira.mongodb.org/browse/SERVER-36330
Gautam Malik

MongoDB 4.2 (attualmente in beta, RC4) supporta transazioni di grandi dimensioni. Rappresentando le transazioni tra più voci di oplog, sarai in grado di scrivere più di 16 MB di dati in una singola transazione ACID (soggetto al tempo di esecuzione massimo predefinito di 60 secondi esistente). Puoi provarli ora - mongodb.com/download-center/community
Grigori Melnik

MongoDB 4.2 è ora GA con il pieno supporto delle transazioni distribuite. mongodb.com/blog/post/…
Grigori Melnik

83

Vivere senza transazioni

Le transazioni supportano le proprietà ACID ma sebbene non ci siano transazioni in MongoDB, abbiamo operazioni atomiche. Bene, le operazioni atomiche significano che quando lavori su un singolo documento quel lavoro verrà completato prima che qualcun altro veda il documento. Vedranno tutte le modifiche che abbiamo apportato o nessuna di esse. E usando le operazioni atomiche, spesso puoi realizzare la stessa cosa che avremmo realizzato usando le transazioni in un database relazionale. E la ragione è che, in un database relazionale, dobbiamo apportare modifiche su più tabelle. Di solito le tabelle che devono essere unite e quindi vogliamo farlo tutto in una volta. E per farlo, poiché ci sono più tabelle, dovremo iniziare una transazione e fare tutti quegli aggiornamenti e poi terminare la transazione. Ma conMongoDB, incorporeremo i dati, dal momento che li pre-uniremo ai documenti e sono questi ricchi documenti che hanno una gerarchia. Spesso possiamo realizzare la stessa cosa. Ad esempio, nell'esempio del blog, se volessimo assicurarci di aggiornare atomicamente un post sul blog, possiamo farlo perché possiamo aggiornare l'intero post sul blog in una sola volta. Dove come se fosse un gruppo di tabelle relazionali, probabilmente dovremmo aprire una transazione in modo da poter aggiornare la raccolta di post e la raccolta di commenti.

Quindi quali sono i nostri approcci che possiamo adottare MongoDBper superare la mancanza di transazioni?

  • ristruttura - ristruttura il codice, in modo che stiamo lavorando all'interno di un singolo documento e sfruttando le operazioni atomiche che offriamo all'interno di quel documento. E se lo facciamo, allora di solito siamo pronti.
  • implementare nel software : possiamo implementare il blocco nel software creando una sezione critica. Siamo in grado di costruire un test, testare e impostare usando trova e modifica. Possiamo costruire semafori, se necessario. E in un certo senso, è così che funziona il mondo più grande. Se ci pensiamo, se una banca ha bisogno di trasferire denaro a un'altra banca, non vivono nello stesso sistema relazionale. Ognuno di essi ha spesso i propri database relazionali. E devono essere in grado di coordinare tale operazione anche se non possiamo iniziare la transazione e terminare la transazione attraverso quei sistemi di database, solo all'interno di un sistema all'interno di una banca. Quindi ci sono certamente modi in cui il software aggira il problema.
  • tollerare : l'approccio finale, che spesso funziona nelle moderne app Web e in altre applicazioni che raccolgono un'enorme quantità di dati, è solo tollerare un po 'di incoerenza. Un esempio sarebbe, se stiamo parlando di un feed di amici su Facebook, non importa se tutti vedono il tuo aggiornamento del muro contemporaneamente. Se okey, se una persona è in ritardo di alcuni battiti per alcuni secondi e raggiungono. Spesso non è fondamentale in molti progetti di sistemi che tutto sia mantenuto perfettamente coerente e che tutti abbiano una visione perfettamente coerente e la stessa del database. Quindi potremmo semplicemente tollerare un po 'di incoerenza che è in qualche modo temporanea.

Update, findAndModify, $addToSet(All'interno di un aggiornamento) e $push(all'interno di un aggiornamento) operazioni operano atomicamente in un singolo documento.


2
Mi piace il modo in cui questa risposta fa, invece di continuare a chiedermi se dovremmo tornare al DB relazionale. Grazie @xameeramir!
DonnyTian,

3
una sezione critica del codice non funzionerà se si dispone di più di un server, è necessario utilizzare un servizio di blocco distribuito esterno
Alexander Mills

@AlexanderMills Puoi approfondire per favore?
Zameer,

Answere sembra essere la trascrizione del video da qui: youtube.com/watch?v=_Iz5xLZr8Lw
Fritz

Penso che questo vada bene fino a quando non saremo limitati a dover operare su un'unica raccolta. Ma non possiamo mettere tutto in un unico documento a causa di vari motivi (dimensioni del documento o se stai usando riferimenti). Penso che potremmo aver bisogno di transazioni.
user2488286

24

Controllare questo fuori, da Tokutek. Sviluppano un plugin per Mongo che promette non solo transazioni ma anche un aumento delle prestazioni.


@Giovanni Bitliner. Tokutek da allora è stato acquisito da Percona e sul link che hai fornito, non vedo alcun riferimento a qualsiasi informazione su ciò che è accaduto dal post. Sai cosa è successo ai loro sforzi? Ho mandato l'indirizzo e-mail su quella pagina per scoprirlo.
Tyler Collier,

Di cosa hai bisogno in particolare? Se hai bisogno della tecnologia toku applicata a Mongodb prova github.com/Tokutek/mongo , se hai bisogno della versione mysql forse l'hanno aggiunta alla loro versione standard di Mysql che di solito forniscono
Giovanni Bitliner

Come posso integrare tokutek con nodejs.
Manoj Sanjeewa,

11

Portalo al punto: se l'integrità transazionale è un must, allora non usare MongoDB ma usa solo componenti nel sistema che supportano le transazioni. È estremamente difficile creare qualcosa sopra il componente al fine di fornire funzionalità simili a ACID per componenti non ACID compatibili. A seconda dei singoli casi d'uso, può essere sensato separare le azioni in azioni transazionali e non transazionali in qualche modo ...


1
Immagino tu intenda che NoSQL può essere usato come database sidekick con RDBMS classico. Non mi piace l'idea di mescolare NoSQL e SQL nello stesso progetto. Aumenta la complessità e forse introduce anche problemi non banali.
NagyI,

1
Le soluzioni NoSQL vengono utilizzate raramente da sole. I negozi di documenti (mongo e couch) sono probabilmente l'unica esecuzione da questa regola.
Karoly Horvath,

7

Ora qual è il problema con quello? MongoDB può eseguire aggiornamenti atomici su un solo documento. Nel flusso precedente potrebbe accadere che si insinui un qualche tipo di errore e che il messaggio venga archiviato nel database ma il saldo dell'utente non venga ridotto e / o la transazione non venga registrata.

Questo non è davvero un problema. L'errore che hai citato è un errore logico (bug) o IO (rete, errore del disco). Questo tipo di errore può lasciare sia i negozi senza transazione che quelli transazionali in uno stato non coerente. Ad esempio, se ha già inviato SMS ma durante la memorizzazione si è verificato un errore del messaggio, non è possibile ripristinare l'invio di SMS, il che significa che non verrà registrato, il saldo dell'utente non verrà ridotto, ecc.

Il vero problema qui è che l'utente può trarre vantaggio dalle condizioni di gara e inviare più messaggi di quanti ne consenta il suo saldo. Questo vale anche per RDBMS, a meno che non si esegua l'invio di SMS all'interno della transazione con il blocco del campo di saldo (che sarebbe un grande collo di bottiglia). Come possibile soluzione per MongoDB sarebbe findAndModifyinnanzitutto utilizzare per ridurre il saldo e verificarlo, se è negativo non consentire l'invio e il rimborso dell'importo (incremento atomico). Se positivo, continua a inviare e nel caso in cui non riesca a rimborsare l'importo. La raccolta della cronologia del saldo può anche essere mantenuta per aiutare a correggere / verificare il campo del saldo.


Grazie per questa ottima risposta! So che se utilizzo archivi di transazione in grado di gestire i dati possono essere danneggiati a causa del sistema SMS che non ho il controllo. Tuttavia, con Mongo esiste la possibilità che si verifichino anche errori di dati interni. Diciamo che il codice cambia il saldo dell'utente con findAndModify, il saldo diventa negativo ma prima che io possa correggere l'errore si verifica un errore e l'applicazione deve essere riavviata. Immagino tu intenda che dovrei implementare qualcosa di simile al commit in due fasi basato sulla raccolta delle transazioni e fare controlli di correzione regolari sul database.
NagyI,

9
Non è vero, i negozi transazionali eseguiranno il rollback se non esegui un commit finale.
Karoly Horvath,

9
Inoltre, non invii SMS e poi accedi a DB, è semplicemente sbagliato. Prima memorizza tutto nel DB ed esegui un commit finale, quindi puoi inviare il messaggio. A questo punto qualcosa potrebbe non riuscire, quindi è necessario un cron job per verificare che il messaggio sia stato effettivamente inviato, se non tentare di inviare. Forse una coda di messaggi dedicata sarebbe meglio per questo. Ma tutto si riduce alla possibilità di inviare SMS in modo transazionale ...
Karoly Horvath,

@ Nagy: Sì, questo è ciò che intendevo dire. Uno deve scambiare i benefici delle transazioni per facilità di scalabilità. Fondamentalmente l'applicazione deve aspettarsi che due documenti in raccolte diverse possano trovarsi in uno stato incoerente ed essere pronti a gestirlo. @yi_H eseguirà il rollback ma lo stato non sarà più effettivo (le informazioni sul messaggio andranno perse). Questo non è molto meglio che avere solo dati parziali (come il saldo ridotto ma nessuna informazione sui messaggi o viceversa).
pingw33n,

Vedo. Questo non è in realtà un semplice vincolo. Forse dovrei imparare di più su come i sistemi RDBMS effettuano le transazioni. Puoi consigliare qualche tipo di materiale o libro online dove posso leggere su questi?
NagyI,

6

Il progetto è semplice, ma devi supportare le transazioni per il pagamento, il che rende il tutto difficile. Quindi, ad esempio, un sistema di portale complesso con centinaia di raccolte (forum, chat, annunci, ecc ...) è in qualche modo più semplice, perché se perdi un forum o una voce di chat, a nessuno importa davvero. Se, d'altra parte, perdi una transazione di pagamento che è un problema serio.

Quindi, se vuoi davvero un progetto pilota per MongoDB, scegline uno che sia semplice da questo punto di vista.


Grazie per aver spiegato. Triste sentirlo. Mi piace la semplicità di NoSQL e l'uso di JSON. Stiamo cercando un'alternativa a ORM ma sembra che dobbiamo attenerci per un po '.
NagyI,

Puoi dare qualche buona ragione per cui MongoDB è meglio di SQL per questa attività? Il progetto pilota sembra un po 'sciocco.
Karoly Horvath,

Non ho detto che MongoDB sia migliore di SQL. Vogliamo semplicemente sapere se è meglio di SQL + ORM. Ma ora sta diventando più chiaro che non sono competitivi in ​​questo tipo di progetti.
NagyI,

6

Le transazioni sono assenti in MongoDB per validi motivi. Questa è una di quelle cose che rendono MongoDB più veloce.

Nel tuo caso, se la transazione è un must, mongo non sembra adatto.

Può essere RDMBS + MongoDB, ma ciò aggiungerà complessità e renderà più difficile la gestione e il supporto dell'applicazione.


1
Esiste ora una distribuzione di MongoDB chiamata TokuMX che utilizza la tecnologia frattale per offrire un miglioramento delle prestazioni di 50x e offre contemporaneamente il pieno supporto delle transazioni ACID: tokutek.com/tokumx-for-mongodb
OCDev

9
Come potrebbe mai una transazione non essere un "must". Non appena hai bisogno di 1 semplice caso in cui devi aggiornare 2 tabelle, improvvisamente mongo non è più adatto? Ciò non lascia affatto molti casi d'uso.
Mr_E,

1
@Mr_E d'accordo, ecco perché MongoDB è un po 'stupido :)
Alexander Mills,

6

Questo è probabilmente il miglior blog che ho trovato sull'implementazione di funzionalità simili a transazioni per mongodb.!

Flag di sincronizzazione: ideale per copiare semplicemente i dati da un documento master

Coda dei lavori: scopo molto generale, risolve il 95% dei casi. La maggior parte dei sistemi deve comunque avere almeno una coda di lavoro in giro!

Commit a due fasi: questa tecnica garantisce che ogni entità abbia sempre tutte le informazioni necessarie per raggiungere uno stato coerente

Log riconciliazione: la tecnica più solida, ideale per i sistemi finanziari

Controllo delle versioni: fornisce isolamento e supporta strutture complesse

Leggi questo per maggiori informazioni: https://dzone.com/articles/how-implement-robust-and


Includi le parti pertinenti della risorsa collegata necessaria per rispondere alla domanda nella tua risposta. Così com'è, la tua risposta è molto suscettibile al marciume del link (cioè se il sito web collegato scende o cambia la tua risposta è potenzialmente inutile).
mech,

Grazie @mech per il suggerimento
Vaibhav,

4

È tardi, ma penso che questo aiuterà in futuro. Uso Redis per fare una coda per risolvere questo problema.

  • Requisito: l'
    immagine seguente mostra 2 azioni che devono essere eseguite contemporaneamente ma la fase 2 e la fase 3 dell'azione 1 devono essere completate prima dell'inizio della fase 2 dell'azione 2 o opposta (una fase può essere una richiesta REST api, una richiesta del database o eseguire il codice javascript ... ). inserisci qui la descrizione dell'immagine

  • In che modo una coda ti aiuta a
    fare in modo che ogni codice di blocco tra lock()e release()in molte funzioni non funzionerà contemporaneamente, rendili isolati.

    function action1() {
      phase1();
      queue.lock("action_domain");
      phase2();
      phase3();
      queue.release("action_domain");
    }
    
    function action2() {
      phase1();
      queue.lock("action_domain");
      phase2();
      queue.release("action_domain");
    }
  • Come costruire una coda
    Mi concentrerò solo su come evitare la parte conditon della gara quando costruisco una coda sul sito di backend. Se non conosci l'idea di base della coda, vieni qui .
    Il codice seguente mostra solo il concetto, è necessario implementarlo in modo corretto.

    function lock() {
      if(isRunning()) {
        addIsolateCodeToQueue(); //use callback, delegate, function pointer... depend on your language
      } else {
        setStateToRunning();
        pickOneAndExecute();
      }
    }
    
    function release() {
      setStateToRelease();
      pickOneAndExecute();
    }

Ma devi isRunning() setStateToRelease() setStateToRunning()isolare se stesso, altrimenti dovrai affrontare di nuovo le condizioni della razza. Per fare ciò ho scelto Redis per scopi ACID e scalabile.
Il documento Redis parla della sua transazione:

Tutti i comandi in una transazione sono serializzati ed eseguiti in sequenza. Non può mai accadere che una richiesta emessa da un altro cliente sia servita nel mezzo dell'esecuzione di una transazione Redis. Ciò garantisce che i comandi vengano eseguiti come un'unica operazione isolata.

P / s:
io uso Redis perché il mio servizio lo usa già, è possibile utilizzare qualsiasi altro supporto per l'isolamento per farlo.
Il action_domainnel mio codice è sopra per quando hai bisogno solo dell'azione 1 chiama dall'utente A blocca l'azione 2 dell'utente A, non bloccare l'altro utente. L'idea è mettere una chiave unica per il blocco di ogni utente.


Avresti ricevuto più voti se il tuo punteggio fosse già stato più alto. Ecco come la maggior parte qui pensa. La tua risposta è utile nel contesto della domanda. Ti ho votato.
Mukus,

3

Le transazioni sono ora disponibili in MongoDB 4.0. Esempio qui

// Runs the txnFunc and retries if TransientTransactionError encountered

function runTransactionWithRetry(txnFunc, session) {
    while (true) {
        try {
            txnFunc(session);  // performs transaction
            break;
        } catch (error) {
            // If transient error, retry the whole transaction
            if ( error.hasOwnProperty("errorLabels") && error.errorLabels.includes("TransientTransactionError")  ) {
                print("TransientTransactionError, retrying transaction ...");
                continue;
            } else {
                throw error;
            }
        }
    }
}

// Retries commit if UnknownTransactionCommitResult encountered

function commitWithRetry(session) {
    while (true) {
        try {
            session.commitTransaction(); // Uses write concern set at transaction start.
            print("Transaction committed.");
            break;
        } catch (error) {
            // Can retry commit
            if (error.hasOwnProperty("errorLabels") && error.errorLabels.includes("UnknownTransactionCommitResult") ) {
                print("UnknownTransactionCommitResult, retrying commit operation ...");
                continue;
            } else {
                print("Error during commit ...");
                throw error;
            }
       }
    }
}

// Updates two collections in a transactions

function updateEmployeeInfo(session) {
    employeesCollection = session.getDatabase("hr").employees;
    eventsCollection = session.getDatabase("reporting").events;

    session.startTransaction( { readConcern: { level: "snapshot" }, writeConcern: { w: "majority" } } );

    try{
        employeesCollection.updateOne( { employee: 3 }, { $set: { status: "Inactive" } } );
        eventsCollection.insertOne( { employee: 3, status: { new: "Inactive", old: "Active" } } );
    } catch (error) {
        print("Caught exception during transaction, aborting.");
        session.abortTransaction();
        throw error;
    }

    commitWithRetry(session);
}

// Start a session.
session = db.getMongo().startSession( { mode: "primary" } );

try{
   runTransactionWithRetry(updateEmployeeInfo, session);
} catch (error) {
   // Do something with error
} finally {
   session.endSession();
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.