2014-10-17 4 views
7

Там было много написано об этой теме:Hibernate автоматически перезапускает транзакции при блокировке?

я нахожу особенно интересным последний принятый ответ:

Если вы используете InnoDB или любую строку уровень транзакционного СУБД, то возможно, что какая-либо операция записи может привести к тупиковой ситуации, даже в совершенно нормальных ситуациях. Большие таблицы, большие записи и длинные транзакционные блоки часто увеличивают вероятность взаимоблокировок . В вашей ситуации это, вероятно, их комбинация.

Это будет означать, что мы никогда не сможем предотвратить их, но только иметь дело с ними. Это правда? Интересно, можете ли вы когда-либо предотвратить блокировки на сайте с 1000 человек в Интернете, которые вызывают операции записи БД.

Гугл по теме не имеет интересных результатов. Только один я нашел это (http://www.coderanch.com/t/415119/ORM/databases/Deadlock-problems-Hibernate-Spring-MS):

public class RestartTransactionAdviser implements MethodInterceptor { 
    private static Logger log = Logger.getLogger(RestartTransactionAdviser.class); 

    public Object invoke(MethodInvocation invocation) throws Throwable { 
     return restart(invocation, 1); 
    } 

    private Object restart(MethodInvocation invocation, int attempt) throws Throwable { 
     Object rval = null; 
     try { 
      rval = invocation.proceed(); 
     } catch (Exception e) { 
      Throwable thr = ExceptionUtils.getRootCause(e); 
      if (thr == null) { 
       throw e; 
      } 

      if (StringUtils.contains(thr.getMessage(), "deadlock") || StringUtils.contains(thr.getMessage(), "try restarting transaction") || StringUtils.contains(thr.getMessage(), 
        "failed to resume the transaction")) { 
       if (attempt > 300) { 
        throw e; 
       } 
       int timeout = RandomUtils.nextInt(2000); 
       log.warn("Transaction rolled back. Restarting transaction."); 
       log.debug("Spleep for " + timeout); 
       log.debug("Restarting transaction: invocation=[" + invocation + "], attempt=[" + attempt + "]"); 
       Thread.sleep(timeout); 
       attempt++; 
       return restart(invocation, attempt); 
      } else { 
       throw e; 
      } 
     } 
     return rval; 
    } 
} 

С другой стороны, я серьезно сомневаюсь, качество такого решения. Можете ли вы рассказать о том, что было бы лучше всего справляться с тупиками? Как бороться с взаимоблокировками в банках и корпоративных приложениях?

+1

И каковы ваши сомнения в таком решении? Это АОП, улавливающее исключения и повторные попытки в определенных ситуациях.Хотя 300 попыток могут быть немного крутыми. Spring также имеет небольшой проект, [Spring Retry] (https://github.com/spring-projects/spring-retry) (также используемый Spring Integration и Spring Batch для такой логики). –

+0

И действительно ли это лучший способ перезапустить транзакции? На самом деле не существует способа предотвратить их использование в базах данных большой нагрузки? –

+1

И что не так с повторением. Вы можете попробовать и предотвратить их, изолируя базу данных, но таким образом ваше приложение будет сканировать ... –

ответ

4

Сессия Hibernate влечет кэш первого уровня transaction write-behind. Это позволяет вам выполнять постобработку изменений до последнего ответственного момента, тем самым уменьшая интервалы обнаружения блокировки (что происходит даже в READ_COMMITTED isolation level).

Это означает, что вам необходимо свести к минимуму все время транзакции, и я могу порекомендовать использовать FlexyPool для таких усилий. Вы должны убедиться, что все транзакции максимально коротки, чтобы сократить интервалы блокировки, чтобы улучшить масштабируемость.

Блокировка вводит последовательные операции, а в соответствии с Amdahl's law масштабируемость обратно пропорциональна общей фракции серийных операций.

Мой совет заключается в первой работе по сокращению интервалов между транзакциями. Индексирование сократит время запроса. ORM могут генерировать ужасные запросы, поэтому убедитесь, что ваш integration testsverify expected queries against actual executed ones.

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

Когда все транзакции максимально коротки, и вам все еще нужно больше параллелизма, вы можете перейти к горизонтальной масштабируемости. Сначала вы можете начать с синхронной стратегии репликации ведущего-ведомого и перенаправить считывание на подчиненный узел, сохраняя мастер для транзакций записи.

Смежные вопросы