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