PlayFramework:捕获死锁并重新发布事务

时间:2011-09-06 15:24:35

标签: java playframework deadlock

我正在运行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! Documentation

  

Play会自动为您管理交易。它将为每个HTTP请求启动一个事务,并在发送HTTP响应时提交它。如果您的代码抛出异常,则事务将自动回滚。

来自MySQL Documentation

  

您必须编写应用程序,以便在由于死锁而回滚时,它们始终准备重新发布事务。

我的问题:
我的游戏中的方式和位置!应用程序可以捕获这些回滚事务,并处理它们(选择重新发布它们,忽略它们等等)?

更新
虽然我最终接受了接受的答案中的建议,并寻找死锁的原因(你知道MySQL外键约束增加了死锁的可能性吗?现在我做了!),这里有一些代码对我有用捕获并重新发出失败的保存。

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

3 个答案:

答案 0 :(得分:3)

您可以使用自定义增强器并增强插件中的所有控制器。

例如,增强器添加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");
    //..
  }  
}

答案 1 :(得分:2)

在大多数死锁情况下,您只能执行回滚并尝试重新启动。在Web应用程序中,这应该是一个非常不寻常的案例。您可以在Play中做什么

  • 捕捉异常
  • 在您的代码中处理交易

使用JPA.em(),您将获得EntityManager。您可以查看JPAPlugin以查看游戏如何处理交易。首先,我将评估为什么会出现死锁,如果这真的是一个真实的情况,服务器可以处理智能。

答案 2 :(得分:0)

我根据@xedon工作为你做了重试,建立了一个play1 module