Из http://static.springsource.org/spring/docs/2.0.x/reference/transaction.html
Команда Spring рекомендует аннотировать только конкретные классы с помощью @Transactional
аннотации, а не аннотировать интерфейсы. Вы, конечно, можете разместить@Transactional
аннотацию на интерфейсе (или методе интерфейса), но это будет работать только так, как вы ожидаете, если вы используете прокси на основе интерфейса. Тот факт, что аннотации не наследуются, означает, что если вы используете прокси на основе классов, тогда настройки транзакции не будут распознаваться инфраструктурой прокси на основе классов, и объект не будет заключен в транзакционный прокси (что было бы определенно плохо ) . Поэтому, пожалуйста, следуйте совету команды Spring и аннотируйте только конкретные классы (и методы конкретных классов) с помощью @Transactional
аннотации.
Примечание. Поскольку этот механизм основан на прокси-серверах, будут перехватываться только вызовы «внешних» методов, поступающие через прокси. Это означает, что «самовызов», то есть метод внутри целевого объекта, вызывающий какой-либо другой метод целевого объекта, не приведет к фактической транзакции во время выполнения, даже если вызванный метод отмечен @Transactional
!
(Курсив добавлен к первому предложению, другой ударение из оригинала.)
JdkDynamicAopProxy
все консультанты по компонентам проходят через каждый вызов метода (см. ТакжеDefaultAdvisorChainFactory#getInterceptorsAndDynamicInterceptionAdvice()
), который в случае настройки декларативной транзакции включаетBeanFactoryTransactionAttributeSourceAdvisor
. В свою очередьTransactionAttributeSourcePointcut#matches()
вызывается, который должен собирать информацию о транзакции. Ему передается целевой класс, и он всегда может проходить через все интерфейсы, реализуемые этим классом. Теперь: почему это не может работать надежно?@Transactional
аннотаций применима? Так что, хотя это все возможно , я не виню Spring. jira.springsource.org/browse/SPR-975Вы можете поместить их в интерфейс, но имейте в виду, что в некоторых случаях транзакции могут не выполняться. См. Второй совет в разделе 10.5.6 документации Spring:
По этой причине я бы рекомендовал поставить их на реализацию.
Кроме того, для меня транзакции кажутся деталью реализации, поэтому они должны быть в классе реализации. Представьте, что у вас есть реализации оболочки для ведения журнала или тестирования (макеты), которые не обязательно должны быть транзакционными.
источник
Spring рекомендует аннотировать конкретные реализации вместо интерфейса. Использование аннотации в интерфейсе не является неправильным, просто можно злоупотребить этой функцией и непреднамеренно обойти ваше объявление @Transaction.
Если вы отметили что-то транзакционное в интерфейсе, а затем весной сослались на один из его реализующих классов в другом месте, не совсем очевидно, что объект, который создает Spring, не будет учитывать аннотацию @Transactional.
На практике это выглядит примерно так:
public class MyClass implements MyInterface { private int x; public void doSomethingNonTx() {} @Transactional public void toSomethingTx() {} }
источник
Поддержка @Transactional в конкретных классах:
Я предпочитаю создавать решение в основном из трех частей: API, реализация и Интернет (при необходимости). Я изо всех сил стараюсь, чтобы API был как можно более легким / простым / POJO, сводя к минимуму зависимости. Это особенно важно, если вы играете в распределенной / интегрированной среде, где вам нужно много делиться API.
Для установки @Transactional требуются библиотеки Spring в разделе API, что IMHO неэффективно. Поэтому я предпочитаю добавлять его в Реализацию, в которой выполняется транзакция.
источник
Ввести его в интерфейс - это нормально, если все предполагаемые разработчики вашего IFC заботятся о данных TX (транзакции - это не проблемы, с которыми имеют дело только базы данных). Если метод не заботится о TX (но вам нужно поместить его туда для Hibernate или чего-то еще), поместите его в impl.
Кроме того, было бы лучше разместить
@Transactional
методы в интерфейсе:public interface FooService { @Transactional(readOnly = true) void doSmth(); }
источник