Механизм повтора для оптимистичной блокировки (весенние данные + JPA)

Мы решили использовать оптимистическую блокировку в нашем веб-приложении, чтобы увеличить параллелизм и не использовать пессимистическую блокировку.

Сейчас мы ищем решения для повторных попыток.

Мы хотели бы как можно меньше влиять на нашу текущую кодовую базу.

Одно из решений, которое мы видели в Интернете, — это использование перехватчика повторных попыток с аннотацией для пометки метода как допускающего повторную попытку.

Проблема в том, что мы хотели бы аннотировать методы, на которых есть аннотация @Transactional, но перехватчик по какой-то причине не может повторить их. (перехватчик идеально повторяет нетранзакционные методы.)

So:

1) Существуют ли какие-либо альтернативы для повторной попытки, которые окажут минимальное влияние на наш код?

2) Есть ли документация\учебники для этого решения?

3) Можно ли вообще повторить аннотированный метод @Transactional?

Ваше здоровье!


person Urbanleg    schedule 10.02.2014    source источник


Ответы (3)


Ad 3.

Вы можете использовать Spring Retry, чтобы повторить метод transacted, когда проверка номера версии или временной метки не удалась (возникает оптимистическая блокировка).

Конфигурация

@Configuration
@EnableRetry
public class RetryConfig {

}

использование

@Retryable(StaleStateException.class)
@Transactional
public void doSomethingWithFoo(Long fooId){
    // read your entity again before changes!
    Foo foo = fooRepository.findOne(fooId);

    foo.setStatus(REJECTED)  // <- sample foo modification

} // commit on method end

Используйте @Transactional (propagation = Propagation.REQUIRES_NEW) для повторной попытки только кода из аннотированного метода.

person MariuszS    schedule 07.08.2017
comment
«SQLException: заявление закрыто». произошло при увольнении. - person xiemeilong; 30.01.2018
comment
@xiemeilong У меня была та же ошибка, что и у вас, с Hibernate 5.0.x. Ушло с 5.2.14.Final. Мне потребовался почти день, чтобы понять это. :( - person Jean-François Beauchef; 11.03.2018
comment
@ Jean-FrançoisBeauchef Большое спасибо, я попробую позже. - person xiemeilong; 12.03.2018

У вас есть два способа добиться этого следующим образом

Восстановление после исключения оптимистичной блокировки в спящем режиме

ИЛИ

Использование Spring AOP для повторной попытки неудачного идемпотента Параллельные операции

Надеюсь, что это поможет вам..!

person Ashish Jagtap    schedule 10.02.2014
comment
Ашиш, мы уже пробовали второе решение, по-видимому, оно не работает, когда вы используете его для транзакционных методов, вы знаете, почему? - person Urbanleg; 10.02.2014
comment
Я точно следовал тому, что написано в josiahgore. blogspot.in/2011/02/, а затем я аннотировал метод службы с помощью @RetryConcurrentOperation(exception = HibernateOptimisticLockingFailureException.class, retries = 12). Теперь, поскольку метод аннотирован с помощью @Transactional, он не работает, он дает обычное исключение оптимистичной блокировки, для нетранзакционного метода, если я его аннотирую - он работает. - person Urbanleg; 10.02.2014

Причина, по которой ваша повторная попытка не сработает, заключается в том, что приоритет @Transactional выше, чем @Aspect.

Вы должны сделать @Aspect более высоким приоритетом, реализовав Ordered в классе TryAgainAspect.

Класс перехватчика:

@Aspect
@Component
public class TryAgainAspect implements Ordered {

private int maxRetries;
private int order = 1;

public void setMaxRetries(int maxRetries) {
    this.maxRetries = maxRetries;
}

public int getOrder() {
    return this.order;
}

@Pointcut("@annotation(IsTryAgain)")
public void retryOnOptFailure() {
}

@Around("retryOnOptFailure()")
public Object doConcurrentOperation(ProceedingJoinPoint pjp) throws Throwable {
    MethodSignature msig = (MethodSignature) pjp.getSignature();
    Object target = pjp.getTarget();
    Method currentMethod = target.getClass().getMethod(msig.getName(), msig.getParameterTypes());
    IsTryAgain annotation = currentMethod.getAnnotation(IsTryAgain.class);
    this.setMaxRetries(annotation.tryTimes());

    int numAttempts = 0;
    do {
        numAttempts++;
        try {
            return pjp.proceed();
        } catch (ObjectOptimisticLockingFailureException | StaleObjectStateException exception) {
            exception.printStackTrace();
            if (numAttempts > maxRetries) {
                throw new NoMoreTryException("System error, all retry failed");
            } else {
                System.out.println("0 === retry ===" + numAttempts + "times");
            }
        }
    } while (numAttempts <= this.maxRetries);

    return null;
}

}

Испробовать снова:

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface IsTryAgain {
    int tryTimes() default 5;
}

Ваш метод класса обслуживания должен добавить аннотацию @IsTryAgain и @Transactional

@IsTryAgain
@Transactional(rollbackFor = Exception.class)
public Product buyProduct(Product product) {
// your business logic 
}
person Lynn Ge    schedule 13.07.2020