PlayFramework: поймать тупик и перевыпустить транзакцию - PullRequest
3 голосов
/ 06 сентября 2011

Я запускаю приложение Play! и отлаживаю тупик.

Сообщения об ошибках, которые я вижу, записываются из Play!являются:
Deadlock found when trying to get lock; try restarting transaction
Could not synchronize database state with session
org.hibernate.exception.LockAcquisitionException: Could not execute JDBC batch update

Из Играть!Документация

Play будет автоматически управлять транзакциями для вас.Он начнет транзакцию для каждого HTTP-запроса и подтвердит его при отправке HTTP-ответа.Если ваш код вызывает исключение, транзакция автоматически откатывается.

Из документации MySQL

вы должны написать свои приложения так, чтобы они быливсегда готов перевыпустить транзакцию, если она откатывается из-за тупика.

Мой вопрос:
Как и где в моей игре!может ли приложение перехватить эти откатные транзакции и обработать их (выбрать переиздание, игнорировать их и т. д ...)?

Обновлено
Пока я в конечном итоге воспользовался советомв принятом ответе и поиске причины тупика (знаете ли вы, что ограничения внешнего ключа MySQL увеличивают вероятность взаимоблокировки? Теперь я знаю!), вот некоторый код, который работал для меня, чтобы отловить и заново выпустить неудачное сохранение.

boolean success = false;
int tries = 0;
while (!success && tries++ < 3) {
    try {
        updated.save();
        success = true;
    } catch (javax.persistence.PersistenceException e) {
        pause(250);  
    }
}

Ответы [ 3 ]

3 голосов
/ 27 декабря 2011

Вы можете использовать собственный Enhancer и улучшать все контроллеры в вашем плагине.

Например, Enhancer добавляет блок catch и перезапускает вызов запроса. Это более надежно для запроса перезапуска, чем только часть логики внутри контроллера:

package plugins;
..
final public class ReliableTxPlugin extends PlayPlugin {
  public void enhance(final ApplicationClasses.ApplicationClass applicationClass) throws Exception {
    new TxEnhancer().enhanceThisClass(applicationClass);
  }
}



package enhancers;
..
class TxEnhancer extends Enhancer {

  public static void process(PersistenceException e) throws PersistenceException {
    final Throwable cause = e.getCause();
    if (cause instanceof OptimisticLockException || cause instanceof StaleStateException) {
      final EntityTransaction tx = JPA.em().getTransaction();
      if (tx.isActive()) {
        tx.setRollbackOnly();
      }
      Http.Request.current().isNew = false;
      throw new Invoker.Suspend(250);
    }
    throw e;
  }    
  public void enhanceThisClass(final ApplicationClass applicationClass) throws Exception {
    // .. general encahcer code   
    ctMethod.addCatch("enhancers.TxEnhancer.process(_e);return;",
    classPool.makeClass("javax.persistence.PersistenceException"), "_e");
    //..
  }  
}
2 голосов
/ 06 сентября 2011

В большинстве случаев тупика вы можете только сделать откат и попробовать перезапустить. Однако в Webapp это должно быть действительно необычным случаем. То, что вы можете сделать в игре, это

  • поймать исключение
  • обработайте транзакцию в вашем коде

С JPA.em() вы получите EntityManager. Вы можете заглянуть в JPAPlugin, чтобы увидеть, как play обрабатывает транзакцию. Однако прежде всего я бы оценил, почему существует тупик и действительно ли это реалистичная ситуация, с которой сервер может справиться с умом.

0 голосов
/ 03 июля 2014

Я построил модуль play1 на основе работы @xedon, выполнив для вас попытку.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...