Étant donné que le programmeur est obligé d'attraper toute l'exception vérifiée, je dois jeter une exception vérifiée en cas de problème. Je voudrais renter sur l'une de ces attentes. Écriture rollbackFor=Exception.class
on Chaque annotation @Transactional
est très sujette à l'erreur, alors je voudrais dire printemps, que: "Chaque fois que j'écris @Transactional
, je veux dire @Transactional(rollbackFor=Exception.class)
".
Je sais que je pourrais créer une annotation personnalisée, mais cela semble non naturel.
Il y a donc un moyen de dire printemps comment il devrait gérer des excpètes vérifiés globalement?
Je sais que je pourrais créer une annotation personnalisée, mais cela semble non naturel.
Non, c'est exactement le cas d'utilisation pour une annotation personnalisée. Voici une citation de Annotations de raccourci personnalisées dans la référence de printemps:
Si vous trouvez que vous utilisez à plusieurs reprises des mêmes attributs avec @TransAderal sur de nombreuses méthodes différentes, le support méta-annotation de Spring vous permet de définir des annotations de raccourci personnalisées pour vos cas d'utilisation spécifiques.
Et voici un exemple d'annotation pour votre cas d'utilisation:
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Transactional(rollbackFor=Exception.class)
public @interface MyAnnotation {
}
Annotez maintenant vos services et/ou méthodes avec @MyAnnotation
(vous penserez à un meilleur nom). Ceci est une fonctionnalité bien testée qui fonctionne par défaut. Pourquoi réinventer la roue?
L'approche avec une annotation personnalisée semble bonne et directe, mais si vous ne voulez réellement pas l'utiliser, vous pouvez créer une personnalisation TransactionAttributeSource
pour modifier l'interprétation de @Transactional
:
public class RollbackForAllAnnotationTransactionAttributeSource
extends AnnotationTransactionAttributeSource {
@Override
protected TransactionAttribute determineTransactionAttribute(
AnnotatedElement ae) {
TransactionAttribute target = super.determineTransactionAttribute(ae);
if (target == null) return null;
else return new DelegatingTransactionAttribute(target) {
@Override
public boolean rollbackOn(Throwable ex) {
return true;
}
};
}
}
Et au lieu de <tx:annotation-driven/>
Vous le configurez manuellement comme suit (voir la source de AnnotationDrivenBeanDefinitionParser
):
<bean id = "txAttributeSource"
class = "RollbackForAllAnnotationTransactionAttributeSource" />
<bean id = "txInterceptor"
class = "org.springframework.transaction.interceptor.TransactionInterceptor">
<property name = "transactionManagerBeanName" value = "transactionManager" />
<property name = "transactionAttributeSource" ref = "txAttributeSource" />
</bean>
<bean
class = "org.springframework.transaction.interceptor.BeanFactoryTransactionAttributeSourceAdvisor">
<property name="transactionAttributeSource" ref = "txAttributeSource" />
<property name = "adviceBeanName" value = "txInterceptor" />
</bean>
Aussi vous avez besoin <aop:config/>
ou <aop:aspectj-autoproxy />
.
Notez cependant que de telles substitutions peuvent être déroutantes pour les autres développeurs qui s'attendent à ce qu'un comportement normal de @Transactional
.
On dirait que vous pouvez configurer un conseil transactionnel basé sur un nom de méthode comme celui-ci: (à partir de The Spring 2.0 Docs )
Les types d'exception marquent exactement une transaction pour la restauration peuvent être configurés. Retrouvez ci-dessous un extrait de configuration XML qui démontre comment on configurait la restauration d'un type d'exception vérifié et spécifique à l'application.
<tx:advice id="txAdvice" transaction-manager="txManager">
<tx:attributes>
<tx:method name="get*" read-only="false" rollback-for="NoProductInStockException"/>
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
Vous pouvez:
throw new RuntimeException(checkedException)
MethodInterceptor
(ou @AroundInvoke
, ou tout autre moyen de créer des aspects au printemps), déclarez-le à être exécuté avant la <tx:annotation-driven />
en précisant order="1"
et order="2"
et attraper et envelopper là-bas.