Откат на каждое проверенное исключение, когда я говорю @Transactional - PullRequest
33 голосов
/ 13 сентября 2010

Поскольку программист вынужден отлавливать все проверенные исключения, я выбрасываю проверенные исключения в случае возникновения каких-либо проблем. Я хотел бы откат на любое из этих ожиданий. Запись rollbackFor=Exception.class в каждой @Transactional аннотации очень подвержена ошибкам, поэтому я хотел бы сказать Spring, что: «всякий раз, когда я пишу @Transactional, я имею в виду @Transactional(rollbackFor=Exception.class)».

Я знаю, что могу создать собственную аннотацию, но это кажется неестественным.

Так есть ли способ рассказать пружине, как она должна обрабатывать проверенные исключения глобально ?

Ответы [ 4 ]

52 голосов
/ 13 сентября 2010

Пользовательские аннотации ярлыков

Я знаю, что могу создать кастом аннотации, но это кажется неестественным.

Нет, это именно тот случай использования пользовательской аннотации. Вот цитата из пользовательских аннотаций ярлыков в Spring Reference:

Если вы обнаружите, что неоднократно используете те же атрибуты с @Transactional на разных методы, затем метааннотация Spring поддержка позволяет определять пользовательские горячие аннотации для вашего конкретного варианты использования.

Пример кода

А вот примерная аннотация для вашего варианта использования:

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Transactional(rollbackFor=Exception.class)
public @interface MyAnnotation {
}

Теперь аннотируйте свои услуги и / или методы с помощью @MyAnnotation (вы придумаете более подходящее имя). Это хорошо проверенная функциональность, которая работает по умолчанию. Зачем изобретать велосипед?

15 голосов
/ 13 сентября 2010

Подход с пользовательской аннотацией выглядит хорошо и просто, но если вы на самом деле не хотите его использовать, вы можете создать пользовательский TransactionAttributeSource для изменения интерпретации @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;
            }
        };
    }
}

Ивместо <tx:annotation-driven/> вы настраиваете его вручную следующим образом (см. источник 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>

Также вам необходимо <aop:config/> или <aop:aspectj-autoproxy />.

Однако обратите внимание, чтоПереопределения могут сбивать с толку других разработчиков, которые ожидают нормального поведения @Transactional.

3 голосов
/ 13 сентября 2010

Похоже, что вы можете настроить совет транзакции на основе имени метода следующим образом: (из документы Spring 2.0 )

Какие именно типы исключений помечают транзакцию для отката, могутбыть настроенным.Ниже приведен фрагмент конфигурации XML, который демонстрирует, как можно настроить откат для проверенного типа исключения для конкретного приложения.

<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>
3 голосов
/ 13 сентября 2010

Вы можете:

  • поймать и обернуть проверенное исключение в исключение без проверки - throw new RuntimeException(checkedException)
  • создайте прокси вокруг метода, используя MethodInterceptor (или @AroundInvoke, или любые другие средства для создания аспектов весной), объявите его выполненным до <tx:annotation-driven />, указав order="1" и order="2" и поймать и завернуть туда.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...