Hibernate会在死锁时自动重启事务吗?

7

这个话题已经有很多人写过了:

我特别感兴趣的是最后一个被接受的答案:

如果您使用InnoDB或任何行级事务RDBMS,则可能会发生死锁,即使在完全正常的情况下也是如此。大表格,大写作和长事务块通常会增加死锁发生的可能性。在您的情况下,这可能是这些因素的结合。

这意味着我们永远无法防止死锁,只能处理它们。这是真的吗? 我想知道是否可以防止1000人在线调用写DB操作的网站死锁。

在谷歌上搜索这个话题并没有得到任何有趣的结果。我只找到了这个(http://www.coderanch.com/t/415119/ORM/databases/Deadlock-problems-Hibernate-Spring-MS):

public class RestartTransactionAdviser implements MethodInterceptor {
    private static Logger log = Logger.getLogger(RestartTransactionAdviser.class);

    public Object invoke(MethodInvocation invocation) throws Throwable {
        return restart(invocation, 1);
    }

    private Object restart(MethodInvocation invocation, int attempt) throws Throwable {
        Object rval = null;
        try {
            rval = invocation.proceed();
        } catch (Exception e) {
            Throwable thr = ExceptionUtils.getRootCause(e);
            if (thr == null) {
                throw e;
            }

            if (StringUtils.contains(thr.getMessage(), "deadlock") || StringUtils.contains(thr.getMessage(), "try restarting transaction") || StringUtils.contains(thr.getMessage(),
                    "failed to resume the transaction")) {
                if (attempt > 300) {
                    throw e;
                }
                int timeout = RandomUtils.nextInt(2000);
                log.warn("Transaction rolled back. Restarting transaction.");
                log.debug("Spleep for " + timeout);
                log.debug("Restarting transaction: invocation=[" + invocation + "], attempt=[" + attempt + "]");
                Thread.sleep(timeout);
                attempt++;
                return restart(invocation, attempt);
            } else {
                throw e;
            }
        }
        return rval;
    }
}

另一方面,我严重怀疑这种解决方案的质量。能否详细说明并解释如何最好地处理死锁?在银行和企业应用程序中如何处理死锁?


1
你对这种解决方案有什么疑虑吗?它是AOP捕获异常并在特定情况下重试。尽管300次重试可能有点过分。Spring还有一个小项目,Spring Retry(也被Spring Integration和Spring Batch用于这种逻辑)。 - M. Deinum
而且尝试重新启动事务真的是最好的方法吗?在高负载数据库中,难道没有一种防止它们发生的方法吗? - Vojtěch
1
重试有什么问题呢?你可以尝试通过隔离数据库来防止它们,但这样会使你的应用程序变得缓慢... - M. Deinum
相关问题:http://stackoverflow.com/questions/26844162/methodinterceptor-for-hibernate-transactions - Vojtěch
1个回答

4
Hibernate会话涉及一个事务write-behind的一级缓存。这使您可以将更改推迟到最后负责的时刻,因此减少锁定获取间隔(即使在READ_COMMITTED隔离级别中也会发生)。
这意味着您必须尽量缩短所有事务时间,我可以建议使用FlexyPool来实现这样的努力。您需要确保所有事务尽可能短,以减少锁定间隔,从而提高可伸缩性。
锁定引入了串行操作,根据Amdahl's law,可扩展性与总串行操作分数成反比。
我的建议是首先减少交易间隔。索引将减少查询时间。ORM可能会生成糟糕的查询,因此请确保您的集成测试 验证实际执行的预期查询
类似p6spy这样的工具非常方便计时查询,请确保您也使用它。
当所有交易尽可能简短,但仍需要更多并发性时,您可以转向水平可扩展性。您可以首先采用同步主从复制策略,并将读取重定向到节点从服务器,同时保留主服务器用于写入交易。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接