web-dev-qa-db-fra.com

Transaction de printemps: restauration sur exception ou Throwable

Je me demande s'il est logique d'utiliser au lieu de

@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)

utiliser Throwable

@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Throwable.class)

Si je comprends bien, la capture de Error nous aidera à nous comporter correctement même en cas de problème grave. Ou peut-être que cela n'aiderait pas?

15
Igor Konoplyanko

Si je comprends bien, la capture d'une erreur nous aidera à nous comporter correctement même en cas de problème grave. Ou peut-être que cela n'aiderait pas?

Vous n'avez pas besoin de spécifier explicitement rollbackFor = Throwable.class, car le printemps annulera par défaut la transaction si un Error se produit.

Voir 12.5.3 Annulation d'une transaction déclarative

Dans sa configuration par défaut, le code d'infrastructure de transaction de Spring Framework ne marque une transaction pour restauration que dans le cas d'exceptions non vérifiées au moment de l'exécution; c'est-à-dire lorsque l'exception levée est une instance ou une sous-classe de RuntimeException. (Les erreurs entraîneront également - par défaut - un retour en arrière) . Les exceptions vérifiées qui sont levées à partir d'une méthode transactionnelle n'entraînent pas de restauration dans la configuration par défaut.

Ou jetez un œil à DefaultTransactionAttribute

public boolean rollbackOn(Throwable ex) {
    return (ex instanceof RuntimeException || ex instanceof Error);
}
25
René Link

Puisque vous utilisez @Transactional, nous pouvons supposer en toute sécurité que vous effectuez vos opérations de base de données via Spring, Hibernate ou d'autres wrappers JDBC. Ces wrappers JDBC ne génèrent généralement pas d'exceptions vérifiées, ils génèrent des exceptions d'exécution qui encapsulent les types JDBC SQLException.

@Transactional est configuré pour restaurer, par défaut, uniquement lorsqu'une exception non vérifiée est levée.

Considérons un cas d'utilisation comme celui-ci

@Transactional
public void persistAndWrite(Bean someBean) throws IOException {
    // DB operation
    getSession().save(someBean); 

    // File IO operation which throws IOException
    someFileService.writeToFile(someBean); 
}

Vous ne voudriez pas nécessairement annuler l'opération DB simplement parce que nous n'avons pas pu écrire quelque chose dans un fichier.

De même

@Transactional
public void persistAndThrowOutOfMemory(Bean someBean)  {
    // DB operation
    getSession().save(someBean);

    // consumes all memory, throws OutOfMemoryError
    someService.hugeOperationThrowsOutOfMemoryError(); 
}

Vous ne voudriez pas nécessairement annuler l'entité enregistrée simplement parce que certains services entraînent une consommation excessive de mémoire.

@Transactional vous donne l'option. Utilisez-le le cas échéant.

4

La valeur par défaut de la restauration est l'enregistrement sur l'exception d'erreur, mais lorsque vous vous inscrivez try{}catch{} manuellement, il remplace l'erreur, donc dans ce cas, utilisez

catch {
        TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
      }

pour le faire manuellement ou supprimer try catch

vous pouvez également enregistrer le type d'exception dans les annotations transactionnelles telles que:

@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
1
Ali.Mojtehedy

Je ne sais pas si c'est possible ou pas mais la manipulation de Throwables comme Errors est un mauvais style de programmation, ce n'est pas la responsabilité des développeurs de gérer ce genre d'erreurs fatales. Il peut toujours arriver de mauvaises choses que vous ne pouvez pas gérer. Vous devez gérer les exceptions vérifiées si nécessaire, qui sont connues de votre système comme un certain type d'erreurs logiques.

0
Arsen Alexanyan