Blog ENI : Toute la veille numérique !
Accès illimité 24h/24 à tous nos livres & vidéos ! 
Découvrez la Bibliothèque Numérique ENI. Cliquez ici
💥 Les 22 & 23 novembre : Accès 100% GRATUIT
à la Bibliothèque Numérique ENI. Je m'inscris !
  1. Livres et vidéos
  2. MongoDB
  3. Les transactions multidocuments
Extrait - MongoDB Comprendre et optimiser l'exploitation de vos données (avec exercices et corrigés) (2e édition)
Extraits du livre
MongoDB Comprendre et optimiser l'exploitation de vos données (avec exercices et corrigés) (2e édition) Revenir à la page d'achat du livre

Les transactions multidocuments

Introduction

Les transactions multidocuments garantissent l’intégrité des données, car si une seule des opérations qu’elles contiennent échoue, alors c’est toute la transaction qui échoue ; il est ainsi impossible de laisser notre base de données dans un état intermédiaire qui menacerait la cohérence même des informations qu’elle contient. On dit pour cette raison qu’une transaction est atomique (c’est tout ou rien).

Ces transactions sont indépendantes les unes des autres et exécutées de manière parfaitement isolée, ce qui signifie que tout changement intervenant durant une transaction ne sera visible à l’extérieur de celle-ci qu’une fois qu’elle sera validée et ses données enregistrées de façon durable.

Nous venons d’énoncer ce que l’on appelle dans le jargon des bases de données les « propriétés ACID » : Atomicité - Cohérence - Isolation - Durabilité.

Apparues avec la version 4.0 de MongoDB et ciblant uniquement les replica sets, les transactions se sont étendues aux clusters shardés depuis la version 4.2, où elles ont été rebaptisées transactions distribuées.

Créons à présent notre première transaction ! Pour ne pas avoir à créer de replica set local, nous allons utiliser un cluster sur Atlas, la solution cloud de MongoDB disponible...

Les sessions

Transactions et sessions sont très fortement couplées comme vous avez pu le constater sur le code précédent : une transaction est exécutée dans le cadre d’une session, qui elle ne peut avoir plus d’une transaction ouverte simultanément. L’interruption d’une session, souhaitée ou non, conduit à l’annulation de toute transaction en cours sur celle-ci.

Voyons les différentes parties liées à la session. Tout d’abord sa création depuis la connexion en cours à la base de données (méthode getMongo()) :

var session = db.getMongo().startSession() 

Ensuite, le démarrage d’une transaction liée à cette session nouvellement créée :

session.startTransaction() 

Notre transaction est ensuite validée ou bien interrompue. Pour la valider, il faut utiliser commitTransaction comme ceci :

session.commitTransaction() 

Pour interrompre une transaction et donc ne réaliser aucune des opérations qui s’y trouvaient, il faut utiliser abortTransaction :

session.abortTransaction() 

Enfin, il faut fermer la session, quel qu’ait pu être le destin de notre transaction :

session.endSession() 

Depuis la session, nous avons également pu récupérer des liens vers nos collections et les stocker dans des variables, le tout à...

Un exemple : la transaction bancaire

Excusez par avance le manque d’originalité de l’exemple qui va suivre, mais le scénario de la transaction bancaire reste LE cas le plus souvent utilisé (et le plus parlant !) lorsque l’on évoque les transactions, surtout dans les bases de données relationnelles, il est vrai ! Nous allons commencer par créer une nouvelle base de données nommée mabanque. Sur notre cluster Atlas, nous allons pour cela cliquer sur le bouton Create Database avant de renseigner son nom ainsi que celui de la toute première collection que nous allons créer dedans, à savoir comptes :

images/07EP11.png
images/07EP12.png

Une fois cette première collection créée, nous en créons une seconde, nommée cette fois mouvements. Si la première contient quelques informations élémentaires sur les comptes bancaires de nos clients fictifs (un numéro, un solde), la seconde journalise l’ensemble des flux financiers qui ont eu lieu sur ceux-ci à une date donnée. Il nous suffit pour cela de cliquer sur l’icône portant le signe « + » à côté du nom de notre base de données :

images/07EP13.png

Nous avons maintenant une base de données et ses deux collections prêtes à l’emploi, alimentons la collection comptes en exécutant des insertions depuis la ligne de commande MongoDB :

Atlas atlas-572dv1-shard-0 [primary] test> use mabanque 
switched to db mabanque 
Atlas atlas-572dv1-shard-0 [primary] mabanque> db.comptes.insertany([ 
      {"numcompte": "FR761111222233334444", "solde": 1000},  
      {"numcompte": "FR76111122223333555", "solde": 1000} 
  ]) 
{ 
  acknowledged: true, 
  insertedIds: { 
    '0': ObjectId("65d47916eaa5b922b5a3ca25"), 
    '1': ObjectId("65d47916eaa5b922b5a3ca26") 
  } 
} 

La collection comptes étant maintenant approvisionnée en documents, nous allons pouvoir nous atteler à la mise en œuvre de notre transaction. Celle-ci sera contenue dans une fonction JavaScript que nous allons appeler...

Conflits d’écriture

Lorsqu’une transaction T1 s’apprête à effectuer des modifications sur un document, il se peut que celui-ci soit déjà en cours de modification par une transaction T2. Le cas échéant, un verrou (lock) est posé par T2 jusqu’à ce que cette transaction soit terminée. Si T1 n’arrive pas à obtenir de verrou sur le document sur lequel il est en concurrence avec T2, elle patientera, mais échouera passé un délai de 5 millisecondes si elle ne peut pas s’accaparer les verrous.

Les verrous d’écriture ne sont pas les mêmes que les verrous de lecture, ils sont les seuls à pouvoir éventuellement générer des conflits. Ainsi, des documents en cours de modification par une transaction pourront être lus sans problème : ils apparaîtront simplement dans un état qui ne sera potentiellement pas le même que celui dans lequel ils seront une fois la transaction terminée. De même que la lecture d’un document n’entraînera pas le blocage d’une transaction s’apprêtant à en modifier l’état.

Limitation des transactions

Ce mécanisme présente quelques limites dans MongoDB :

  • La durée d’une transaction multidocument est par défaut limitée à 60 secondes. Passée cette durée, la transaction sera purement et simplement interrompue par MongoDB. Si vous souhaitez modifier cette limite, il vous faudra jouer avec transactionLifetimeLimitSeconds dans la configuration de votre serveur.

  • Les commandes d’administration sont interdites dans une transaction (createUser, getParameter, etc.).

  • Les lectures et les écritures sont interdites dans les collections local, admin ou encore config.

  • Les écritures dans les collections préfixées par system sont également interdites. 

  • Il n’est pas possible d’écrire dans des collections plafonnées (capped collections).

Les transactions constituent une fonctionnalité très utilisée dans les systèmes de gestion de bases de données relationnelles et manquaient cruellement dans la plupart des alternatives logicielles au tout-relationnel. Cette attente fut comblée lorsque les transactions multidocuments sont apparues avec la version 4 de MongoDB. Pour être parfaitement honnête, sauf si vos applications sont d’une très grande complexité, il y a de grandes chances que vous n’ayez jamais à vous en servir, car le modèle...