Мы имеем:
@Transactional(propagation = Propagation.REQUIRED)
public class MyClass implementes MyInterface { ...
MyInterface имеет отдельный метод: go()
.
То, когда идут () выполняется, мы запускаем новую транзакцию, которая фиксирует/откатывает, когда метод завершен - это прекрасно.
Теперь скажем, в движении () мы называем закрытый метод в MyClass, который имеет @Transactional(propagation = Propagation.REQUIRES_NEW
. Кажется, что Spring "игнорирует" аннотацию REQUIRES_NEW и не запускает новую транзакцию. Я полагаю, что это вызвано тем, что Spring AOP работает на интерфейсном уровне (MyInterface) и не прерывает вызовов к методам MyClass. Это корректно?
Там какой-либо путь состоит в том, чтобы запустить новую транзакцию в движении () транзакция? Единственный путь состоит в том, чтобы назвать другой управляемый компонент Spring, которому настроили транзакции как REQUIRES_NEW?
Обновление: Добавление этого, когда клиенты выполняются go()
они делают так через ссылку на интерфейс, не класс:
@Autowired
MyInterface impl;
impl.go();
Из справки по Spring 2.5:
При использовании прокси аннотация
@Transactional
должна применяться только к методам с публичной видимостью. Если вы аннотируете защищенные, приватные или видимые в пакете методы с аннотацией@Transactional
, то ошибка не возникнет не возникнет, но аннотированный метод не будет отображать настроенные транзакционные настройки.
Поэтому Spring игнорирует аннотацию @Transactional
на непубличных методах.
Также,
В режиме прокси (который используется по умолчанию), только "внешние" вызовы методов, поступающие через прокси, будут перехвачены. Это означает, что "самопризыв", т.е. метод внутри целевого объекта вызывает другой метод целевого объекта, не приведет к фактической транзакции во время выполнения, даже если вызываемый метод помечен
@Transactional
!
Поэтому даже если вы сделаете свой метод публичным
, вызов его из метода того же класса не приведет к началу новой транзакции.
Вы можете использовать режим aspectj
в настройках транзакции, чтобы код, связанный с транзакцией, был вплетен в класс и не создавался прокси во время выполнения.
Более подробно см. в справочном документе.
Другой возможный способ сделать это - получить spring proxy класса в самом классе и вызывать методы на нем, а не this
:
@Service
@Transactional(propagation = Propagation.REQUIRED)
public class SomeService {
@Autowired
private ApplicationContext applicationContext;
private SomeService getSpringProxy() {
return applicationContext.getBean(this.getClass());
}
private void doSomeAndThenMore() {
// instead of
// this.doSometingPublicly();
// do the following to run in transaction
getSpringProxy().doSometingPublicly();
}
public void doSometingPublicly() {
//do some transactional stuff here
}
}
@Transactional
будет замечен, только если он находится в общедоступном
методе, из-за того, как работает Spring AOP.
Однако вы можете программно запустить новую транзакцию , если хотите, используя TransactionTemplate
, например
TransactionTemplate txTemplate = new TransactionTemplate(txManager);
txTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
txTemplate.execute(new TransactionCallback<Object>() {
public Object doInTransaction(TransactionStatus status) {
// do stuff
}
});