Работает ли атрибут Spring @Transactional над частным методом?


Если у меня есть @Transactional -аннотация на частный метод в Spring bean, имеет ли аннотация какой-либо эффект?

Если @Transactional аннотация находится на общедоступном методе, он работает и открывает транзакцию.

public class Bean {
  public void doStuff() {
     doPrivateStuff();
  }
  @Transactional
  private void doPrivateStuff() {

  }
}

...

Bean bean = (Bean)appContext.getBean("bean");
bean.doStuff();
6 154

6 ответов:

ответа на ваш вопрос нет - @Transactional не будет иметь никакого эффекта, если используется для аннотирования частные методы. Генератор прокси будет игнорировать их.

это задокументировано в руководство по пружинам глава 10.5.6:

видимость метода и @Transactional

при использовании прокси, вы должны применить элемент @Transactional аннотации только к методам с публичной видимостью. Если вы комментируете защищенные, частные или пакет-видимый методы с @Transactional аннотация, без ошибок поднимается, но аннотированный метод не показывает настроенный транзакционные настройки. Рассмотрим использование AspectJ (см. ниже), Если вам нужно для аннотирования непубличных методов.

вопрос не является частным или публичным, вопрос в том, как он вызывается и какую реализацию AOP вы используете!

Если вы используете (по умолчанию) Spring Proxy AOP, то все функции AOP, предоставляемые Spring (например @Transational) будет учитываться только в том случае, если вызов проходит через прокси. -- Обычно это происходит, если аннотированный метод вызывается из другое бобовые.

это имеет два последствия:

  • потому что частная методы не должны вызываться из другого компонента (исключение-отражение), их @Transactional аннотация не принимается во внимание.
  • если метод является общедоступным, но он вызывается из того же компонента, он также не будет учитываться (этот оператор корректен только в том случае, если (по умолчанию) используется прокси-сервер Spring AOP).

@See Весенняя ссылка: глава 9.6 9.6 проксирующие механизмы

IMHO вы должны использовать режим aspectJ, а не Весенние прокси, которые преодолеют проблему. А транзакционные аспекты AspectJ вплетены даже в частные методы (проверено на Spring 3.0).

по умолчанию @Transactional атрибут работает только при вызове аннотированного метода по ссылке, полученной из applicationContext.

public class Bean {
  public void doStuff() {
    doTransactionStuff();
  }
  @Transactional
  public void doTransactionStuff() {

  }
}

это откроет транзакцию:

Bean bean = (Bean)appContext.getBean("bean");
bean.doTransactionStuff();

этого не будет:

Bean bean = (Bean)appContext.getBean("bean");
bean.doStuff();

Spring Ссылка: С Помощью @Transactional

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

рассмотрите использование режима AspectJ (см. ниже), если вы ожидаете, что самопроизвольные вызовы также будут обернуты транзакциями. В этом случае в первую очередь не будет прокси; вместо этого целевой класс будет "сплетен" (т. е. его байтовый код будет изменен), чтобы повернуть @Transactional В поведение во время выполнения какой-либо способ.

Да, можно использовать @Transactional на частных методах, но, как упоминали другие, это не будет работать из коробки. Вы должны использовать AspectJ. Мне потребовалось некоторое время, чтобы понять, как заставить его работать. Я поделюсь своими результатами.

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

во-первых, добавьте зависимость для aspectjrt.

<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjrt</artifactId>
    <version>1.8.8</version>
</dependency>

затем добавьте плагин AspectJ, чтобы выполнить фактическое переплетение байт-кода в Maven (это может быть не минимальный пример).

<plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>aspectj-maven-plugin</artifactId>
    <version>1.8</version>
    <configuration>
        <complianceLevel>1.8</complianceLevel>
        <source>1.8</source>
        <target>1.8</target>
        <aspectLibraries>
            <aspectLibrary>
                <groupId>org.springframework</groupId>
                <artifactId>spring-aspects</artifactId>
            </aspectLibrary>
        </aspectLibraries>
    </configuration>
    <executions>
        <execution>
            <goals>
                <goal>compile</goal>
            </goals>
        </execution>
    </executions>
</plugin>

наконец добавьте это в свой класс конфигурации

@EnableTransactionManagement(mode = AdviceMode.ASPECTJ)

Теперь вы должны быть в состоянии использовать @Transactional на частных методах.

одно предостережение к этому подходу: вам нужно будет настроить IDE, чтобы быть в курсе AspectJ в противном случае, если вы запустите приложение через Eclipse, например, он может не работать. Убедитесь, что вы тестируете против прямой сборки Maven в качестве проверки здравомыслия.

пожалуйста, смотрите этот документ:

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

рассмотрите использование режима AspectJ (см. атрибут mode в таблице ниже), если вы ожидаете собственной вызовы быть завернуты также в сделках. В этом случае в первую очередь не будет прокси; вместо этого целевой класс будет соткан (то есть его байтовый код будет изменен), чтобы превратить @Transactional в поведение среды выполнения для любого метода.

----------------------------за

Итак, пыльник - это пользователь BeanSelfAware

ответа нет. Пожалуйста, смотрите Весенняя Ссылка: Использование @Transactional :

на @Transactional аннотация может быть размещена перед определением интерфейса, методом на интерфейсе, определением класса или общественные метод на классе