Где я должен поместить аннотацию @Transactional: в определении интерфейса или в классе реализации? - PullRequest
78 голосов
/ 25 июня 2010

Вопрос из заголовка в коде:

@Transactional (readonly = true)
public interface FooService {
   void doSmth ();
}


public class FooServiceImpl implements FooService {
   ...
}

против

public interface FooService {
   void doSmth ();
}

@Transactional (readonly = true)
public class FooServiceImpl implements FooService {
   ...
}

Ответы [ 5 ]

105 голосов
/ 25 июня 2010

С http://static.springsource.org/spring/docs/2.0.x/reference/transaction.html

Команда Spring рекомендует аннотировать только конкретные классы с помощью аннотации @Transactional, а не аннотировать интерфейсы. Вы, конечно, можете разместить@Transactional аннотация на интерфейсе (или метод интерфейса), но это будет работать только так, как вы ожидаете, если вы используете прокси на основе интерфейса.Тот факт, что аннотации не наследуются , означает, что если вы используете прокси на основе классов, то параметры транзакции не будут распознаваться инфраструктурой прокси на основе классов, и объект не будет заключен в транзакционный прокси (что было бы решительно плохо ).Поэтому, пожалуйста, следуйте советам команды Spring и аннотируйте только конкретные классы (и методы конкретных классов) с помощью аннотации @Transactional.

Примечание. Поскольку этот механизм основан на прокси, только 'внешние'вызовы методов, поступающие через прокси-сервер, будут перехвачены. Это означает, что "самопризыв", то есть метод в целевом объекте, вызывающий какой-либо другой метод целевого объекта, не приведет к реальной транзакции во время выполнениядаже если вызванный метод помечен @Transactional!

(ударение добавлено в первое предложение, другой акцент из оригинала.)

9 голосов
/ 25 июня 2010

Вы можете поместить их в интерфейс, но имейте в виду, что в некоторых случаях транзакции могут не произойти. См. Второй совет в Secion 10.5.6 документа Spring:

Spring рекомендует аннотировать только конкретные классы (и методы конкретных классов) аннотацией @Transactional, а не аннотировать интерфейсы. Вы, конечно, можете разместить аннотацию @Transactional на интерфейсе (или методе интерфейса), но это работает только так, как вы ожидаете, если вы используете прокси на основе интерфейса. Тот факт, что аннотации Java не наследуются от интерфейсов, означает, что если вы используете прокси на основе классов (proxy-target-class = "true") или аспект на основе ткачества (mode = "aspectj"), то параметры транзакции не распознается инфраструктурой прокси и ткачества, и объект не будет помещен в транзакционный прокси-сервер, что будет явно плохо.

По этой причине я бы рекомендовал включить их в реализацию.

Кроме того, для меня транзакции кажутся деталями реализации, поэтому они должны быть в классе реализации. Представьте, что у вас есть реализации-оболочки для ведения журнала или тестовые реализации (макеты), которые не должны быть транзакционными.

8 голосов
/ 25 июня 2010

Рекомендация Spring состоит в том, что вы аннотируете конкретные реализации вместо интерфейса.Использование аннотации в интерфейсе не является неправильным, просто возможно неправильно использовать эту функцию и непреднамеренно обойти декларацию @Transaction.

Если вы пометили что-то транзакционное в интерфейсе и затем обратились к одному из его реализующихв других классах весной не совсем очевидно, что созданный весной объект не будет учитывать аннотацию @Transactional.

На практике это выглядит примерно так:

public class MyClass implements MyInterface { 

    private int x;

    public void doSomethingNonTx() {}

    @Transactional
    public void toSomethingTx() {}

}
1 голос
/ 28 марта 2015

Поддержка @Transactional для конкретных классов:

Я предпочитаю разрабатывать решение, как правило, из 3 разделов: API, Реализация и Web (при необходимости).Я стараюсь изо всех сил поддерживать API как можно более легким / простым / POJO, сводя к минимуму зависимости.Это особенно важно, если вы играете в распределенной / интегрированной среде, где вам приходится много делиться API.

Для размещения @Transactional требуются библиотеки Spring в разделе API, что, по-моему, не эффективно.Поэтому я предпочитаю добавить его в реализацию, где выполняется транзакция.

0 голосов
/ 25 июня 2010

Поместить его в интерфейс хорошо, если все предполагаемые исполнители вашего IFC заботятся о данных TX (транзакции - это не проблемы, с которыми сталкиваются только базы данных).Если метод не заботится о TX (но вам нужно поместить его туда для Hibernate или чего-то еще), включите его в значение.

Кроме того, может быть немного лучше поместить @Transactional наметоды в интерфейсе:

public interface FooService {
    @Transactional(readOnly = true)
    void doSmth();
}
...