Pendant le processus de développement, un bogue a été rencontré. La raison du bogue était que la transaction Spring a soumis des messages de production plus tard que la file d'attente de messages, ce qui entraîne des données incorrectes obtenues lorsque la file d'attente de messages consomme des messages. Cet article présente l'émergence de problèmes et le processus de résolution étape par étape.
1. Problème survenant:
Restauration de scénarios: une méthode dans l'interface, modifiez d'abord l'état de la commande, puis produit des messages à partir de la file d'attente de messages. Le consommateur de la file d'attente de messages obtient l'état de la commande de détection de message et constate que l'état de la commande n'a pas changé.
Code:
@Service (OrderAPI) Classe publique OrderAPIIMPL implémente OrderAPI {@Resource MQService MQService; @OrderDao OrderDao; public void push (String OrderId) {// Mettez à jour l'état de la commande, l'état précédent était 1 UpdateStatus (OrderId, 3); // générer le message mqService.Produce (OrderId); } public viod updateStatus (String OrderId, Integer Status) {OrderDao.upDateStatus (OrderId, Status); }}La raison du problème: toutes les méthodes dans OrderAPI ont des transactions et le type de transaction propagation_requeed, de sorte que le fonctionnement de la méthode push sur les données sera soumis après l'exécution du code push. Avant que la transaction ne soit soumise, le message de file d'attente de message a été généré, de sorte que l'état de la commande consommée dans la requête de file d'attente de messages à partir de la base de données peut être 1. Afin de rendre le bug plus évident, vous pouvez l'ajouter à la fin de la méthode push:
essayez {Thread.Sleep (10000);} Catch (InterruptedException e) {// Todo Block de capture généré automatiquement E.PrintStackTrace ();}De cette façon, vous constaterez que l'état de la commande n'a pas été modifié lorsque le message de consommation est consommé.
2. Solution au problème:
Solution: Lors de la mise à jour des données, créez une nouvelle chose pour vous assurer qu'après l'exécution du code de mise à jour, la transaction qui met à jour la base de données a été engagée. (Assurez-vous que l'opération de base de données a été soumise avant la génération du message)
Selon le schéma ci-dessus, la première chose à laquelle je pense est de modifier directement le type de transaction de la méthode UpdateStatus; J'ai changé le type de transaction de cette méthode en propagation_requires_new (créer une nouvelle transaction, si la transaction existe actuellement, suspendre la transaction actuelle).
Mais il y a deux choses inappropriées à faire:
1. Modification forcée du type de transaction UpdateStaus peut affecter d'autres processus.
2. Ne fonctionne pas, aucune nouvelle transaction n'a été créée dans la méthode UpdateStaus.
Explication sur le deuxième point: Spring ajoute des transactions via BeanNameAutoproxyCreator, qui ne fait qu'ajouter des transactions aux objets Bean. Maintenant, appeler des méthodes à l'intérieur de la classe ne déclenchera pas la création de nouvelles choses.
Donc, après avoir essayé ce qui précède, j'ai créé une nouvelle classe:
@Service ("ORDEREXTAPI") Classe publique ORDERextAPIIMPl {@Resource OrderAPI ORDERAPI; public void updateStatusNewPropagation (String OrderId) {orderAPI.upDateStatus (OrderId); }}et ajouter des transactions propagation_requires_new pour la méthode UpdateStatusNewPropagation
Cette classe est juste pour créer une nouvelle transaction pour la méthode UpdateStaus dans OrderAPI.
Ok, jusqu'à présent, le bug a été résolu.
Cependant, il y a encore des problèmes dans le code: le fonctionnement de la base de données a été soumis, et s'il existe une exception dans le message de production, il est toujours mal pour la logique métier. Par conséquent, il est nécessaire de détecter si la génération de messages est terminée.
Le code dans la commande finale est le suivant:
@Service (OrderAPI) Classe publique OrderAPIIMPL implémente OrderAPI {@Resource MQService MQService; @Resource OrderDao OrderDao; @Resource ORDEREXTAPIIMPl ORDEREXTAPI; public void push (String OrderId) {// Mettez à jour l'état de la commande, l'état précédent était 1 OrdereXtAPI.updateStatusNewPropagation (OrderId, 3); // Générer Message - Produit détectera si une exception se produit. Lorsque 1 est retourné, cela signifie que le message de production réussit. Réponse réponse = mqService.produce (OrderId); if (réponse.getcode ()! = 1) {log.info ("Message de file d'attente Message de production Exception:" + Response.getERRormsg ()) // Message de production Exception, réinitialisez le statut et attendez la prochaine réexécution OrdereXtAPI.updateStatusNewPropagation (OrderId, 1); }} public viod updateStatus (String OrderId, Integer Status) {OrderDao.upDateStatus (OrderId, Status); }}Ce qui précède est tout le contenu de cet article. J'espère que cela sera utile à l'apprentissage de tous et j'espère que tout le monde soutiendra davantage Wulin.com.