Spring Оптимистический Locking:How для повторения транзакционного метода до фиксации успешен

Я использую Spring 2.5 и В спящем режиме, реализация JPA с Java и "контейнером" справилась с Транзакциями.

Я имею "после пользовательского метода" фиксации, который обновляет данные в фоне и потребности, которая будет фиксироваться независимо от ConcurrencyFailureException или StaleObjectStateException исключение, потому что это никогда не будут показывать клиенту. Другими словами, потребность сделать Оптимистическую Блокировку к Пессимистическому. (Мог произойти, если осуществление методов возьмет немного дольше, и кто-то изменил данные в другой транзакции),


Я читал много об идемпотентном материале, повторяю если исключение в поисках DEFAULT_MAX_RETRIES или 6.2.7. Пример или глава 14.5. Повторить. Я также нашел в stackoverflow здесь и здесь.

Я попробовал это:

public aspect RetryOnConcurrencyExceptionAspect {

    private static final int DEFAULT_MAX_RETRIES = 20;
    private int maxRetries = DEFAULT_MAX_RETRIES;

    Object around(): execution( * * (..) ) && @annotation(RetryOnConcurrencyException) && @annotation(Transactional) {

        int numAttempts = 0;
          RuntimeException failureException = null;
          do {
                numAttempts++;
                try {
                    return proceed(); 
                } 
                catch( OptimisticLockingFailureException ex ) {
                    failureException = ex;
                }
                catch(ConcurrencyFailureException ex) {
                    failureException = ex;
                }
                catch( StaleObjectStateException ex) {
                    failureException = ex;
                }
          } while( numAttempts <= this.maxRetries );
          throw failureException;

    }
}

RetryOnConcurrencyException моя Аннотация должна отметить методы, которые должны быть повторены, если исключение происходит. Не работал... Я также попробовал несколько путей как SELECT ... FOR UPDATE, EntityManager.lock(...)

Что лучший способ состоит в том, чтобы избежать устаревших данных, грязные чтения и т.д. такая стратегия с Spring? Повторить?, синхронизировался?, блокировка JPA?, изоляция?, выберите... для обновления? Я не мог заставить это работать и я действительно довольный любой справкой.


Вот некоторый псевдо код, что мне нравится делать:

void doSomething(itemId) {
    select something into A;
    select anotherthing into B;

    // XXX
    item = getItemFormDB( itemId ); // takes long for one user and for other concurrent user it could take less time
    item.setA(A);
    item.setB(B);

    // YYYY
    update item; 
}

Между//XXX и//YYY другая сессия могла изменить объект, затем StaleObjectStateException брошен.

19
задан Community 23 May 2017 в 12:25
поделиться

2 ответа

У меня есть решение, но я считаю его некрасивым. Я ловлю все RuntimeException, и это работает только для новых транзакций. Вы знаете, как это сделать лучше? Вы видите какие-нибудь проблемы?

Сначала я сделал аннотацию:

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface RetryingTransaction {
     int repeatCount() default 20;
}

Затем я сделал перехватчик, подобный этому:

    public class RetryingTransactionInterceptor implements Ordered {
      private static final int DEFAULT_MAX_RETRIES = 20;
      private int maxRetries = DEFAULT_MAX_RETRIES;
      private int order = 1;

      @Resource
      private PlatformTransactionManager transactionManager;

      public void setMaxRetries(int maxRetries) {
          this.maxRetries = maxRetries;
      }
      public int getOrder() {
          return this.order;
      }
      public void setOrder(int order) {
          this.order = order;
      }

      public Object retryOperation(ProceedingJoinPoint pjp) throws Throwable {
          int numAttempts = 0;
          Exception failureException = null;
          do {
                numAttempts++;
                try {
                    DefaultTransactionDefinition def = new DefaultTransactionDefinition();
                    def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
                    TransactionStatus status = transactionManager.getTransaction(def);

                    Object obj = pjp.proceed();

                    transactionManager.commit(status);      

                    return obj;
                } 
                catch( RuntimeException re ) {
                    failureException = re;
                }
          } while( numAttempts <= this.maxRetries );
          throw failureException;
      }
}

Spring applicationConfig.xml:

<tx:annotation-driven transaction-manager="transactionManager" order="10" />

<bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager">
    <property name="transactionSynchronizationName">
        <value>SYNCHRONIZATION_ALWAYS</value>
    </property>
</bean>

<bean id="retryingTransactionInterceptor" class="com.x.y.z.transaction.RetryingTransactionInterceptor">
    <property name="order" value="1" />
</bean>

<aop:config>
    <aop:aspect id="retryingTransactionAspect" ref="retryingTransactionInterceptor">
        <aop:pointcut 
            id="servicesWithRetryingTransactionAnnotation" 
            expression="execution( * com.x.y.z.service..*.*(..) ) and @annotation(com.x.y.z.annotation.RetryingTransaction)"/>
        <aop:around method="retryOperation" pointcut-ref="servicesWithRetryingTransactionAnnotation"/>
    </aop:aspect>
</aop:config>

И метод, аннотированный следующим образом:

@RetryingTransaction
public Entity doSomethingInBackground(params)...
10
ответ дан 30 November 2019 в 05:04
поделиться

Выбрасывая здесь другой вариант: BoneCP ( http://jolbox.com ) поддерживает автоматическое повторение транзакций в случае сбоя (в том числе при выходе из строя БД, сбое сети и т. Д.).

-2
ответ дан 30 November 2019 в 05:04
поделиться
Другие вопросы по тегам:

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