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应用程序来说是不寻常的)或负载非常重时,才会发生死锁。在最后一种情况下,我认为您必须解决性能问题,否则不会出现死锁,而是用户体验不佳。很好。谢谢你有没有想过为此写一个模块?