Подтвердить что ты не робот

Откат по каждому проверенному исключению, когда я говорю @Transactional

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

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

Итак, есть способ рассказать spring, как он должен обрабатывать проверенные действия во всем мире?

4b9b3361

Ответ 1

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

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

Нет, это пример использования пользовательской аннотации. Здесь цитата из Пользовательские ярлыки аннотаций в справочнике Spring:

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

Пример кода

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

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

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

Ответ 2

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

Вы можете:

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

Ответ 4

Похоже, вы можете настроить транзакционный совет на основе имени метода следующим образом: (от 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>