Запуск новой транзакции в бобе Spring

Мы имеем:

@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();
44
задан Marcus Leon 14 June 2010 в 12:22
поделиться

2 ответа

Из справки по 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
    }

}
77
ответ дан 26 November 2019 в 21:45
поделиться

@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
    }
});
42
ответ дан 26 November 2019 в 21:45
поделиться
Другие вопросы по тегам:

Похожие вопросы: