2014-02-09 4 views
2

У меня следующий код в одном из моих услуг:Spring данных - Оптимистичный механизм повтора не работает должным образом

@Override 
@Transactional 
@RetryConcurrentOperation(exception = Exception.class, retries = 12) 
public void test() { 

Player player = this.playerRepository.findPlayerById(1L); 
player.setFirstName("SomeName"); 
} 

механизм повторных попыток я использую тот, который был описан здесь: http://josiahgore.blogspot.co.il/2011/02/using-spring-aop-to-retry-failed.html

проблема, когда я получаю оптимистическую повторную попытку (вторые повторные попытки) я получаю исключение:

Caused by: org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [xxx] 

Интересно это в том, что механизм работает, когда Я удаляю транзакционной аннотацию и внутри, не транзакционной функции я звоню другой транзакционный метод:

// THIS WORKS: 
@Override 
@RetryConcurrentOperation(exception = Exception.class, retries = 12) 
public void test() { 
execute(); 

} 

@Override 
@Transactional 
public void execute() { 
Player player = this.playerRepository.findPlayerById(1L); 
player.setFirstName("SomeName"); 
} 

Любые идеи, почему этот механизм аспект повторных попыток не удается, когда это время вызывается из транзакционной функции?

+0

в конце концов @Transactional работа в этих случаях? Я подумал, что там есть две проблемы: один ват, что транзакционная транзакция не работает для повторных вызовов, а вторая запись в блоге не будет работать для версий, но это был ответ, который вы искали, или это что-то еще? –

+0

Попробуйте это решение: https://stackoverflow.com/a/45543257/516167 – MariuszS

ответ

0

При вызове @Transactionalexecute() из неживой транзакционной test(), тем @Transactional в execute() НЕ будет применяться. Это связано с тем, что это прямой вызов одного метода объекта непосредственно другому, который обходит транзакционный прокси.

Дополнительную информацию о работе прокси и @Transactional см. Здесь answer. С ее помощью не работает.

Обратите внимание также на весну RetryTemplate, которая является весенним решением этой проблемы.

Что касается механизма повтора, это не сработает для случаев, когда используется версия с версией (с столбцом @Version), что является случаем, когда бросается StaleObjectStateException.

Причина в том, что в базе данных был добавлен другой поток, увеличивающий колонку версии.

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

+0

Кажется, что RetryTemplat не отличается общим. Каждый раз, когда я хочу повторить, мне нужно реализовать специальную функцию обратного вызова. – lior

+0

callback позволяет применять некоторую логику восстановления (например, писать в другую таблицу, аномалии журнала в журнальных столах и т. Д.). А где обновления/вставки запускаются в базе данных без @Transactional? –

+0

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