我正在运行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外键约束增加了死锁的可能性吗?现在我做了!),这里有一些代码对我有用捕获并重新发出失败的保存。
boolean success = false;
int tries = 0;
while (!success && tries++ < 3) {
try {
updated.save();
success = true;
} catch (javax.persistence.PersistenceException e) {
pause(250);
}
}
答案 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。