6
votes

Sous impeccableRollBackeXception remplace ma propre exception

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.

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.

Je m'attends à ce que la runtimédie extérieure provoque une annulation de la transaction extérieure, mais le comportement réel est:

  • La transaction externe semble essayer de commettre de commettre, ou au moins vérifier son statut, puis il jette la sensation extra-éducatrice, car la transaction physique était déjà marquée comme Rollbackonly.
  • Avant de lancer cette exception, elle imprime les journaux une autre exception, indiquant que "l'exception d'application remplacée par commettre une exception". Ainsi, l'appelant A reçoit la impressitéRollbackeXException, pas l'exception que b jette.

    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 xxx

    Cependant, cette solution de contournement a fortement couplé Le code avec les transactions API et j'aimerais éviter cela. Toute suggestion?

    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


0 commentaires

3 Réponses :


5
votes

Vous pouvez essayer de définir woodeartonglobalrollbackonly drapeau sur true dans votre abstractplatformtransactionmanager héritier ( hibernatetransactionmanager , par exemple) . Voici sa description:

Définissez s'il faut échouer tôt dans le cas de la transaction marquée dans le monde entier comme annulée uniquement.

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".


1 commentaires

+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)



8
votes

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.

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.


1 commentaires

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?



0
votes

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 { xxx

Remarque: N'oubliez pas que des exceptions non cochées provoquent des retombées dans les transactions à ressort.

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.

code: @Transactional (Rollbackfor = recordexIssSexception.Class) ou avez-vous la classe d'exception étendre RunTimeException.


0 commentaires