java - Hibernate 是否会在死锁时自动重启事务?

标签 java mysql spring hibernate transactions

关于这个话题已经有很多文章了:

我发现最后接受的答案特别有趣:

If you are using InnoDB or any row-level transactional RDBMS, then it is possible that any write transaction can cause a deadlock, even in perfectly normal situations. Larger tables, larger writes, and long transaction blocks will often increase the likelihood of deadlocks occurring. In your situation, it's probably a combination of these.

这意味着我们永远无法阻止它们,只能对付它们。真的吗?我想知道您是否可以在有 1000 人在线调用写数据库操作的网站上防止死锁。

谷歌搜索该主题没有得到任何有趣的结果。我找到的唯一一个是这个 ( 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;
    }
}

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

最佳答案

Hibernate session 需要一个 transaction write-behind一级缓存。这使您能够将更改推迟到最后负责的时刻,从而减少锁定获取间隔(甚至发生在 READ_COMMITTED isolation level 中)。

这意味着您必须尽量减少所有交易时间,我可以推荐使用 FlexyPool为了这样的努力。您需要确保所有事务都尽可能短,以减少锁定间隔,从而提高可伸缩性。

锁定引入串行操作,根据Amdahl's law ,可扩展性与总串行操作分数成反比。

我的建议是首先着手减少交易间隔。索引将减少查询时间。 ORM 可能会生成糟糕的查询,因此请确保您的 integration tests verify expected queries against actual executed ones .

类似p6spy 的工具非常方便地为您的查询计时,因此请确保您也使用它。

当所有事务都尽可能短并且您仍然需要更多并发时,您可以转向水平可扩展性。您可以首先从同步主从复制策略开始,将读取重定向到节点从属节点,同时保留主节点进行写入事务。

关于java - Hibernate 是否会在死锁时自动重启事务?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26424184/

相关文章:

php - 当 mysql_query 返回 false 时

java - 未找到 Servlet-Context : Spring 4 Hibernate 4 Maven JSF PrimeFaces in NetBeans

java - 通过 jdbc 对 sqlite 数据库执行更新有时不起作用

java - 如何在Java中打开文件夹/目录

java - 如何从 firebase 检索键和值并将它们存储在两个单独的变量中

php - 如何为简单的多语言网站(PHP MySQL)构建数据库?

java - 如何使用某些与 SQL 兼容的列类型在 Spring JPA 中存储 Joda 时间(任何)?

bash - 以 n 列的形式输出数据库中的所有表

java - 无法从 Thymeleaf 表单将值发布到 HTTP 请求

spring - 在 Spring Cloud Kafka 中转换消息的最简单方法是什么?