J'ai le scénario étrange suivant avec la gestion des transactions de printemps:
J'ai la méthode A qui appelle la méthode B qui appelle la méthode C, chacune d'entre elles dans une classe différente. Les méthodes B et C sont toutes deux enveloppées avec des transactions. Utilisez la propagation_requiked, donc tandis que le ressort crée deux transactions logiques, il existe une transaction physique dans la DB. P>
Maintenant, dans la méthode C, je jette une décomption de runtimédia. Cela définit la transaction logique interne comme relancement et la transaction physique également. Dans la méthode B, je suis conscient de la possibilité d'une impressité impressionnante. Je ne procède donc pas à s'engager normalement. J'attrape l'exception de c et je jette une autre runtimédiexception. P>
Je m'attends à ce que la runtimédie extérieure provoque une annulation de la transaction extérieure, mais le comportement réel est: p>
J'ai trouvé une solution de contournement pour cela, qui consiste à définir activement la transaction externe sous la forme d'une annulée avant de lancer l'exception p> Cependant, cette solution de contournement a fortement couplé Le code avec les transactions API et j'aimerais éviter cela. Toute suggestion? P> P.s.
Les deux transactions sont censées annuler des exceptions d'exécution. Je n'ai défini aucune exception annulée pour une exception ou quelque chose comme ça p> p>
3 Réponses :
Vous pouvez essayer de définir Définissez s'il faut échouer tôt dans le cas de la transaction marquée dans le monde entier comme annulée uniquement. em> p>
La valeur par défaut est "FALSE", provoquant une imprévu une imprévu accessible à la limite de transaction la plus externe. Changez ce drapeau pour provoquer une impressionnance extra-inscrite dès que le marqueur global de restauration à la restauration n'a été détecté d'abord, même d'une limite de transaction interne. Ote, à partir du printemps 2.0, le comportement échoué pour les marqueurs de restauration globale n'a été unifié: tous les gestionnaires de transactions ne proviendront que par défaut, provoquent une imprévue impressionnante à la limite de transaction la plus externe. Cela permet, par exemple, de poursuivre les tests d'unités, même après l'échec d'une opération et que la transaction ne sera jamais terminée. Tous les gestionnaires de transactions n'échoueront que plus tôt si cet indicateur a été explicitement défini sur "vrai". Em> p> woodeartonglobalrollbackonly code> drapeau sur
true code> dans votre
abstractplatformtransactionmanager code> héritier (
hibernatetransactionmanager code>, par exemple) . Voici sa description: P>
+1 et merci pour l'effort. E-Échecteartonglobalrollbackonly est intéressant, mais j'ai finalement trouvé la cause du problème (voir ma réponse ci-dessous)
J'ai trouvé la cause de ce problème. Il s'avère que la méthodeb a été enveloppée avec un proxy basé sur CGLIB (à l'aide de ressort vieille, PRE 2.0) avant d'être enveloppé dans la transaction. Donc, lorsque je jette une punition à partir d'une méthodeb, cglib finit par lancer une invocationTargetException, qui est en fait une exception vérifiée. P>
Le gestionnaire de transactions de printemps finit par attraper l'exception vérifiée et tente de commettre la transaction, ignorant l'exception d'exécution imbriquée que la méthodétique a lancé. Une fois que j'ai découvert cela, j'ai mis en place le wrapper de transaction à la restauration des exceptions vérifiées également, cela fonctionne maintenant comme prévu. P>
J'ai le même problème. Pouvons-nous retourner pour toutes les exceptions vérifiées et décochées. Y aura-t-il un problème avec cela?
Ajoutez une exception personnalisée qui étend une exception d'exécution et prenez cette exception jusqu'à ce que le contrôleur de l'exception.
La classe publique Customexception étendre RunTimeException { P> Remarque: N'oubliez pas que des exceptions non cochées provoquent des retombées dans les transactions à ressort. P> Que ce qui se passe est que vous attrapez l'exception décochée, la convertissant en une exception vérifiée, puis la propogez-la. Le gestionnaire de transactions ne recule pas pour RecordExistSeXception et pense que votre première transaction a réussi. C'est pourquoi il essaie de sauvegarder vos objets enfants. Vous devriez annoter votre service avec. P> code:
@Transactional (Rollbackfor = recordexIssSexception.Class)
ou avez-vous la classe d'exception étendre RunTimeException. p> p>