Там было много написано об этой теме:Hibernate автоматически перезапускает транзакции при блокировке?
- Restarting transaction in MySQL after deadlock
- Deadlock found when trying to get lock; try restarting transaction : @RetryTransaction
- MySQL JDBC: Is there an option for automatic retry after InnoDB deadlock?
- Working around MySQL error "Deadlock found when trying to get lock; try restarting transaction"
- ... многое другое
я нахожу особенно интересным последний принятый ответ:
Если вы используете 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;
}
}
С другой стороны, я серьезно сомневаюсь, качество такого решения. Можете ли вы рассказать о том, что было бы лучше всего справляться с тупиками? Как бороться с взаимоблокировками в банках и корпоративных приложениях?
И каковы ваши сомнения в таком решении? Это АОП, улавливающее исключения и повторные попытки в определенных ситуациях.Хотя 300 попыток могут быть немного крутыми. Spring также имеет небольшой проект, [Spring Retry] (https://github.com/spring-projects/spring-retry) (также используемый Spring Integration и Spring Batch для такой логики). –
И действительно ли это лучший способ перезапустить транзакции? На самом деле не существует способа предотвратить их использование в базах данных большой нагрузки? –
И что не так с повторением. Вы можете попробовать и предотвратить их, изолируя базу данных, но таким образом ваше приложение будет сканировать ... –