2010-12-09 45 views
18

Référencer Spring documentation:Les meilleures pratiques pour faire reculer les transactions au printemps 3/Mise en veille prolongée

Tout RuntimeException déclencheront rollback, et tout vérifié exception ne

Référencer javapractices.com

Décoché exceptions:

  • représentent des défauts dans le programme (bogues) - arguments souvent invalides passé à une méthode non-privée. Pour citation de Java Programmation Langue, par Gosling, Arnold, et Holmes: « exceptions d'exécution Unchecked représentent des conditions qui, généralement parlant, reflètent des erreurs dans la logique de votre programme et ne peut pas être raisonnablement récupéré à l'exécution temps "
  • sont sous-classes de RuntimeException et sont généralement mis en œuvre utilisant IllegalArgumentException, NullPointerException, ou IllegalStateException
  • une méthode n'est pas obligé d'établir une politique pour les exceptions non vérifiées lancées par sa mise en œuvre (et ils presque toujours ne font pas donc)

exceptions cochés:

  • représentent des conditions non valides dans les zones en dehors de la con immédiate trôle de le programme (d'entrée d'utilisateur non valide, les problèmes de base de données , pannes de réseau, fichiers absents)
  • sont sous-classes d'exception
  • une méthode est tenu d'établir une politique pour toutes les exceptions vérifiées lancées par sa mise en œuvre (soit passer l'exception vérifiée plus haut la pile, ou de le manipuler en quelque sorte)

Si au cours de ma logique métier, je découvre un problème et je veux rollback les changements, je dois lancer une nouvelle course timeException? Ce n'est pas vraiment une exception RuntimeException (exception non vérifiée) puisque je l'ai identifiée dans la logique. Ou peut-être que je suis mal compris ces concepts?

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

Répondre

10

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

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

etc.

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

+1

Comment puis-je retourner quelque chose de ma méthode si je lance une exception? De plus, lancer une exception est assez coûteux. N'y a-t-il aucun moyen de restaurer manuellement la transaction sans déclencher une exception? –

+0

@GuillaumePolet On pourrait dire que si vous faites volontairement un retour en arrière dans le cadre d'un flux de processus métier non exceptionnel, les coûts associés aux annulations dans un SGBDR éclipsent de plusieurs ordres le coût réel ou perçu d'une exception sur un modem moderne. JVM, et le design entier devrait être revisité. Peu importe, si vous n'aimez pas la façon dont fonctionnent les transactions déclaratives ... ne les utilisez pas. La fonctionnalité n'est en aucun cas votre seule option. Vous pouvez toujours utiliser les anciennes transactions de session de mise en veille prolongée roll-your-own. – Affe

4

Il devrait être comme

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

... et * pourquoi * devrait-il être comme ça? – meriton

+0

@meriton Cela fonctionnera pour tout le cas, je veux dire votre but de montrer que ce service lance cette exception sera résolu ainsi que vos choses transactionnelles seront également prises en charge –

2

Je pense qu'il est sûr de dire qu'il existe différentes opinions sur les exceptions qui devraient être vérifiées. Par exemple, considérons cet extrait de Introduction to the Spring Framework:

L'exception d'accès aux données de printemps hiérarchie est basée sur incontrôlées (exécution) exceptions. Ayant travaillé avec Spring sur plusieurs projets je suis de plus en plus convaincu que c'était la bonne décision.

Les exceptions d'accès aux données ne sont généralement pas récupérables. Par exemple, si nous ne pouvons pas se connecter à la base de données, un objet métier particulier est peu susceptible de pouvoir pour contourner le problème. Une exception potentielle est optimiste violations de verrouillage, mais pas toutes les applications utilisent un verrouillage optimiste. Il est généralement mauvais d'être forcé d'écrire le code pour attraper des exceptions fatales que ne peut pas être raisonnablement manipulé. Laisser se propager aux gestionnaires de niveau supérieur comme le servlet ou le conteneur EJB est généralement plus approprié. Toutes les exceptions d'accès aux données Spring sont des sous-classes de DataAccessException, donc si nous faisons choisir d'attraper toutes les exceptions d'accès aux données Spring , nous pouvons facilement le faire.

Notez que si nous voulons récupérer à partir d'une exception d'accès aux données non contrôlé , nous pouvons toujours le faire. Nous pouvons écrire le code pour gérer seulement la condition récupérable . Par exemple, si on considère que seule une violation de verrouillage optimiste est récupérable, nous pouvons écrire un code DAO Spring comme suit:

try {// faire un travail} catch (OptimisticLockingFailureException ex) {//Je suis intéressé par ceci} Si Printemps exceptions d'accès aux données ont été vérifié, nous aurions besoin d'écrire le code suivant. Notez que nous pourrions choisir d'écrire cela de toute façon:

try {// faire un travail} catch (OptimisticLockingFailureException ex) {// Je suis intéressé par ce } catch (DataAccessException ex) {// Fatal; juste le réitérer} Une objectionpotentielle au premier exemple - que le compilateur ne peut pas appliquer la manipulation l'exception potentiellement récupérable - s'applique également à la seconde. Étant donné que nous sommes forcés d'intercepter l'exception de base (DataAccessException), le compilateur n'applique pas de vérification pour une sous-classe (OptimisticLockingFailureException). Ainsi, le compilateur nous forcerait à écrire du code pour gérer un problème irrécupérable , mais ne fournir aucune aide dans , nous forçant à traiter le problème récupérable .

utilisation Printemps d'accès aux données sans contrôle des exceptions est conforme à celle de beaucoup - probablement le plus - avec succès cadres de persistance. (En effet, a été partiellement inspiré par JDO.) JDBC est l'une des rares API d'accès aux données à utiliser exceptions vérifiées. Par exemple, TopLink et JDO, , utilisent exclusivement les exceptions non contrôlées . Mise en veille prolongée passe de vérifié exceptions non vérifiées dans la version 3.

exceptions d'accès aux données sont clairement en dehors du contrôle immédiat du programme, donc selon javapractices, ils doivent être vérifiés. Mais les gens à la source de printemps diffèrent. Et je fais confiance à leur jugement plus que javapractices. Par conséquent, je ne vois rien de mal à lancer une exception non cochée pour indiquer que la transaction doit être annulée. Bien sûr, vous pouvez également utiliser des exceptions vérifiées et configurer l'aspect pour les restaurer également. (voir la réponse d'Affe pour plus de détails)

6

soit annuler par programmation à partir de:

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

ou marquer l'exception pour rollback et manipuler de 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 l'ancien car il garde le code plus simple, mais il est discouraged selon Spring docs:

L'annulation de programme est disponible si vous en avez absolument besoin, mais son utilisation va à l'encontre de l'architecture propre à POJO .