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

Java PlayFramework:捕获死锁并重新发出事务,java,playframework,deadlock,Java,Playframework,Deadlock,我正在运行应用程序并调试死锁 我从播放中看到的错误消息已被记录!是: 尝试获取锁时发现死锁;尝试重新启动事务 无法将数据库状态与会话同步 org.hibernate.exception.LockAcquisitionException:无法执行JDBC批处理更新 从 Play将自动为您管理交易。它将为每个HTTP请求启动一个事务,并在发送HTTP响应时提交它。如果代码抛出异常,事务将自动回滚 从 您必须编写应用程序,以便在事务因死锁而回滚时,它们随时准备重新发出事务 我的问题: 在我的戏里怎么演

我正在运行应用程序并调试死锁

我从播放中看到的错误消息已被记录!是:
尝试获取锁时发现死锁;尝试重新启动事务
无法将数据库状态与会话同步

org.hibernate.exception.LockAcquisitionException:无法执行JDBC批处理更新

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

您必须编写应用程序,以便在事务因死锁而回滚时,它们随时准备重新发出事务

我的问题:
在我的戏里怎么演,在哪里演!应用程序我可以捕获这些回滚事务并处理它们(选择重新发布它们、忽略它们等等)

更新
虽然我最终采纳了公认答案中的建议,并寻找死锁的原因(您知道MySQL外键约束会增加死锁的可能性吗?现在我知道了!),但下面是一些代码,它们帮助我捕获并重新发出失败的保存

boolean success = false;
int tries = 0;
while (!success && tries++ < 3) {
    try {
        updated.save();
        success = true;
    } catch (javax.persistence.PersistenceException e) {
        pause(250);  
    }
}
boolean success=false;
int=0;
而(!success&&trys++<3){
试一试{
更新的.save();
成功=真实;
}catch(javax.persistence.PersistenceException){
暂停(250);
}
}

在大多数死锁情况下,您只能执行回滚并尝试重新启动。然而,在网络应用程序中,这应该是一个非常不寻常的情况。你在游戏中能做的就是

  • 抓住例外
  • 在代码中处理事务

使用
JPA.em()
您将获得EntityManager。您可以查看
JPAPlugin
,了解play如何处理事务。首先,我将评估为什么会出现死锁,以及这是否是服务器能够智能处理的真实情况

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

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

我基于@xedon work为您创建了一个用于重试的应用程序。

我并不反对,但只是好奇:webapps如何使这成为“一个非常不寻常的情况?”我现在正在运行压力测试,死锁错误只是偶尔发生,并且在高并发情况下,这就是为什么我一直在想,只要回滚并重试就足以解决这个问题。您认为我应该寻求更好的解决方案吗?或者您认为我走在了正确的道路上,因为这似乎需要相当特殊的环境才能重现?通常,只有当您有长时间运行的事务(这对于Web应用程序来说是不寻常的)或负载非常重时,才会发生死锁。在最后一种情况下,我认为您必须解决性能问题,否则不会出现死锁,而是用户体验不佳。很好。谢谢你有没有想过为此写一个模块?