Je sais qu'il y a des questions similaires ici, mais elles me disent soit de revenir aux systèmes SGBDR réguliers si j'ai besoin de transactions, soit d'utiliser des opérations atomiques ou une validation en deux phases . La deuxième solution semble le meilleur choix. Le troisième je ne souhaite pas suivre car il semble que beaucoup de choses pourraient mal tourner et je ne peux pas le tester dans tous les aspects. J'ai du mal à refactoriser mon projet pour effectuer des opérations atomiques. Je ne sais pas si cela vient de mon point de vue limité (je n'ai travaillé qu'avec des bases de données SQL jusqu'à présent), ou si cela ne peut pas être fait.
Nous souhaitons tester MongoDB dans notre entreprise. Nous avons choisi un projet relativement simple - une passerelle SMS. Il permet à notre logiciel d'envoyer des SMS au réseau cellulaire et la passerelle fait le sale boulot: communiquer réellement avec les fournisseurs via différents protocoles de communication. La passerelle gère également la facturation des messages. Chaque client qui demande le service doit acheter des crédits. Le système diminue automatiquement le solde de l'utilisateur lorsqu'un message est envoyé et refuse l'accès si le solde est insuffisant. De plus, parce que nous sommes clients de fournisseurs de SMS tiers, nous pouvons également avoir nos propres soldes avec eux. Nous devons également en garder une trace.
J'ai commencé à réfléchir à la façon dont je pouvais stocker les données requises avec MongoDB si je réduisais une certaine complexité (facturation externe, envoi de SMS en file d'attente). Venant du monde SQL, je créerais une table séparée pour les utilisateurs, une autre pour les messages SMS et une pour stocker les transactions concernant le solde des utilisateurs. Disons que je crée des collections séparées pour toutes celles de MongoDB.
Imaginez une tâche d'envoi de SMS avec les étapes suivantes dans ce système simplifié:
vérifier si l'utilisateur a un solde suffisant; refuser l'accès s'il n'y a pas assez de crédit
envoyer et stocker le message dans la collection SMS avec les détails et le coût (dans le système en direct, le message aurait un
status
attribut et une tâche le ramasserait pour la livraison et fixerait le prix du SMS en fonction de son état actuel)diminuer le solde des utilisateurs par le coût du message envoyé
consigner la transaction dans la collection de transactions
Quel est le problème avec ça? MongoDB ne peut effectuer des mises à jour atomiques que sur un seul document. Dans le flux précédent, il peut arriver qu'une sorte d'erreur se glisse et que le message soit stocké dans la base de données, mais le solde de l'utilisateur n'est pas mis à jour et / ou la transaction n'est pas enregistrée.
J'ai eu deux idées:
Créez une collection unique pour les utilisateurs et stockez le solde sous forme de champ, les transactions et messages liés à l'utilisateur en tant que sous-documents dans le document de l'utilisateur. Parce que nous pouvons mettre à jour les documents de manière atomique, cela résout en fait le problème de transaction. Inconvénients: si l'utilisateur envoie de nombreux SMS, la taille du document peut devenir importante et la limite de 4 Mo de document peut être atteinte. Peut-être que je peux créer des documents d'histoire dans de tels scénarios, mais je ne pense pas que ce soit une bonne idée. De plus, je ne sais pas à quelle vitesse le système serait si je transmettais de plus en plus de données au même gros document.
Créez une collection pour les utilisateurs et une pour les transactions. Il peut y avoir deux types de transactions: achat à crédit avec changement de solde positif et messages envoyés avec changement de solde négatif. La transaction peut avoir un sous-document; par exemple, dans les messages envoyés, les détails du SMS peuvent être intégrés dans la transaction. Inconvénients: je ne stocke pas le solde actuel de l'utilisateur, je dois donc le calculer à chaque fois qu'un utilisateur essaie d'envoyer un message pour dire si le message peut passer ou non. Je crains que ce calcul ne devienne lent à mesure que le nombre de transactions stockées augmente.
Je ne sais pas trop quelle méthode choisir. Y a-t-il d'autres solutions? Je n'ai pas trouvé de bonnes pratiques en ligne sur la manière de contourner ce type de problèmes. Je suppose que de nombreux programmeurs qui essaient de se familiariser avec le monde NoSQL sont confrontés à des problèmes similaires au début.