Meilleures pratiques pour l’annulation des transactions au spring 3 / Hibernate

Référence à la documentation Spring :

Toute exception RuntimeException déclenchera une restauration et aucune exception cochée ne sera

Référencement javapractices.com

Exceptions non contrôlées:

  • représentent des défauts dans le programme (bogues) – souvent des arguments non valides transmis à une méthode non privée. Pour citer Java, Langage de programmation, de Gosling, Arnold et Holmes: “Les exceptions d’exécution non vérifiées représentent des conditions qui, en général, reflètent des erreurs dans la logique de votre programme et ne peuvent être raisonnablement récupérées au moment de l’exécution.”
  • sont des sous-classes de RuntimeException et sont généralement implémentées à l’aide de IllegalArgumentException, NullPointerException ou IllegalStateException
  • une méthode n’est pas obligée d’établir une politique pour les exceptions non contrôlées générées par sa mise en œuvre (et ils ne le font presque toujours pas)

Exceptions vérifiées:

  • représentent des conditions non valides dans des zones hors du contrôle immédiat du programme (saisie utilisateur non valide, problèmes de firebase database, pannes de réseau, fichiers absents)
  • sont des sous-classes d’exception
  • une méthode est obligée d’établir une politique pour toutes les exceptions vérifiées levées par son implémentation (soit transmettre l’exception vérifiée plus loin dans la stack, ou la gérer d’une manière ou d’une autre)

Si, au cours de ma logique métier, je découvre un problème et que je souhaite annuler les modifications, je dois générer une nouvelle exception RuntimeException? Ce n’est pas vraiment une exception RuntimeException (exception non contrôlée) puisque je l’ai identifiée dans la logique. Ou peut-être que je comprends mal ces concepts?

Ma vraie question , quelles sont les meilleures pratiques pour annuler une transaction dans mes méthodes de service @Transactional?

Si vous utilisez des exceptions vérifiées, vous les ajoutez simplement à la propriété rollbackFor de votre annotation @Transactional .

 @Transactional(rollbackFor = { MyInvalidUserException.class, MyApplicationException.class }) public void method() throws MyInvalidUserException, MyApplicationException { ... ... } 

etc.

La réponse de org.life.java fonctionne également très bien. C’est une décision académique si vous souhaitez mélanger la gestion de transaction programmatique dans vos transactions déclaratives ou la garder ssortingctement déclarative.

Soit revenir en arrière par programme à partir de:

 @Transactional public void commit() { try { // some business logic... } catch (ConstraintViolationException e) { // sortinggger rollback programmatically TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); } } 

ou marquer l’exception pour la restauration et la gérer depuis l’appelant:

 @Transactional(rollBackFor = TransactionException.class) public void commit() throws ConstraintViolationException{ try { // some business logic... } catch (ConstraintViolationException e) { // handle the exception // re-throw for rollback new TransactionException(e); } } public void doCommit(){ try { commit() } catch (TransactionException e){ // do nothing as already handled } } 

Je préfère le premier car il garde le code plus simple, mais il est découragé selon les documents de Spring:

La restauration programmatique est disponible si vous en avez absolument besoin, mais son utilisation va à l’encontre de la réalisation d’une architecture propre basée sur POJO.

Ça devrait être comme

 @Transactional public void method () throws YourCustomException { try{ //logic }catch(Exception ex){ TransactionAspectSupport.currentTransactionStatus() .setRollbackOnly(); throw(new YourCustomException(ex.getMessage())); } } 

Je pense qu’il est prudent de dire qu’il existe différentes opinions sur les exceptions à vérifier. Par exemple, considérons cet extrait de Introduction au cadre de spring :

La hiérarchie des exceptions d’access aux données Spring est basée sur des exceptions non contrôlées (à l’exécution). Ayant travaillé avec Spring sur plusieurs projets, je suis de plus en plus convaincu que c’était la bonne décision.

Les exceptions d’access aux données ne sont généralement pas récupérables. Par exemple, si nous ne pouvons pas nous connecter à la firebase database, il est peu probable qu’un object métier particulier puisse contourner le problème. Les violations de locking optimistes constituent une exception potentielle, mais toutes les applications ne l’utilisent pas. Il est généralement mauvais d’être obligé d’écrire du code pour intercepter des exceptions fatales impossibles à gérer de manière judicieuse. Les laisser se propager à des gestionnaires de niveau supérieur tels que le servlet ou le conteneur EJB est généralement plus approprié. Toutes les exceptions d’access aux données Spring sont des sous-classes de DataAccessException. Par conséquent, si nous décidons d’attraper toutes les exceptions d’access aux données Spring, nous pouvons facilement le faire.

Notez que si nous voulons récupérer à partir d’une exception d’access aux données non contrôlée, nous pouvons toujours le faire. Nous pouvons écrire du code pour gérer uniquement la condition récupérable. Par exemple, si nous considérons que seule une violation de locking optimiste est récupérable, nous pouvons écrire du code dans un DAO Spring comme suit:

try {// do work} catch (OptimisticLockingFailureException ex) {// Cela m’intéresse} Si les exceptions d’access aux données Spring étaient vérifiées, nous aurions besoin d’écrire le code suivant. Notez que nous pourrions choisir d’écrire cela quand même:

try {// do work} catch (OptimisticLockingFailureException ex) {// je suis intéressé par ce}} catch (DataAccessException ex) {// Fatal; il suffit de le relire} Une objection potentielle au premier exemple – que le compilateur ne peut pas imposer le traitement de l’exception potentiellement récupérable – s’applique également au second. Comme nous sums obligés d’intercepter l’exception de base (DataAccessException), le compilateur n’applique pas de contrôle pour une sous-classe (OptimisticLockingFailureException). Le compilateur nous obligerait donc à écrire du code pour traiter un problème irrécupérable, mais ne fournirait aucune aide pour nous obliger à traiter le problème récupérable.

L’utilisation par Spring d’exceptions d’access non vérifiées est conforme à celle de nombreux frameworks de persistance, probablement les plus réussis. (En effet, il a été partiellement inspiré de JDO.) JDBC est l’une des rares API d’access aux données à utiliser les exceptions vérifiées. TopLink et JDO, par exemple, utilisent exclusivement des exceptions non contrôlées. Hibernate est passé des vérifications aux exceptions non vérifiées dans la version 3.

Les exceptions d’access aux données ne sont clairement pas sous le contrôle immédiat du programme. Selon les pratiques Java, elles doivent donc être vérifiées. Mais les gens à la source du spring diffèrent. Et je fais plus confiance à leur jugement qu’aux pratiques java.

Par conséquent, je ne vois rien de mal à lancer une exception non vérifiée pour indiquer que la transaction doit être annulée. Bien entendu, vous pouvez également utiliser les exceptions vérifiées et configurer l’aspect de manière à les restaurer. (voir la réponse d’Affe pour plus de détails)

Entré dans cette URL pour la gestion des exceptions vérifiées et non vérifiées, la gestion des transactions: ce n’est pas l’approche basée sur les annotations mais c’est bien.

http://javasight.wordpress.com/2009/02/17/understanding-spring-transaction-management-with-checked-and-unchecked-exceptions/