当前位置: 首页 > 面试题库 >

休眠:尝试获取锁时发现死锁

方恺
2023-03-14
问题内容

我在项目中使用了hibernate模式,并且由于非常简单的数据库操作而获得了随机的表观死锁。

有一个堆栈跟踪:https :
//gist.github.com/knyttl/8999006
–让我感到困惑的是,第一个异常是RollbackException,然后是LockAquisition异常。

问题经常发生在类似的条款上:

@Transactional
public void setLastActivity() {
    User user = em.findById(...);
    user.setLastActivity(new Date());
    em.merge(user);
    em.flush();
}

我很困惑,因为我不知道这是Hibernate,MySQL还是C3P0的问题。

我的Hibernate配置:

            <prop key="hibernate.dialect">${database.dialect}</prop>
            <prop key="hibernate.hbm2ddl.auto">${database.structure}</prop>
            <prop key="hibernate.connection.url">${database.connection}</prop>
            <prop key="hibernate.connection.username">${database.username}</prop>
            <prop key="hibernate.connection.password">${database.password}</prop>
            <prop key="hibernate.connection.driver_class">${database.driver}</prop>
            <prop key="hibernate.connection.shutdown">true</prop>
            <prop key="hibernate.connection.writedelay">0</prop>
            <prop key="hibernate.connection.characterEncoding">UTF-8</prop>
            <prop key="hibernate.connection.charSet">UTF-8</prop>
            <prop key="hibernate.show_sql">${database.show_sql}</prop>
            <prop key="hibernate.format_sql">false</prop>
            <prop key="hibernate.ejb.metamodel.generation">disabled</prop>
            <!-- Use the C3P0 connection pool provider -->
            <prop key="hibernate.connection.provider_class">org.hibernate.connection.C3P0ConnectionProvider</prop>
            <prop key="hibernate.c3p0.min_size">0</prop>
            <prop key="hibernate.c3p0.max_size">50</prop>
            <prop key="hibernate.c3p0.timeout">120</prop>
            <prop key="hibernate.c3p0.max_statements">0</prop>
            <prop key="hibernate.c3p0.max_statementsPerConnection">0</prop>
            <prop key="hibernate.c3p0.maxStatementsPerConnection">0</prop>
            <prop key="hibernate.c3p0.idle_test_period">120</prop>
            <prop key="hibernate.c3p0.acquire_increment">1</prop>
            <prop key="hibernate.c3p0.numHelperThreads">8</prop>

编辑1:

  • 我在上面写过,明显的死锁正在发生-这是错误的,只有“试图获取锁时发现死锁”发生。

编辑2:

这些方法也会发生这种情况-需要使用@Transactional进行注释的那些方法:

@Transactional
public void setLastActivity() {
    em.insertNative("table")
           .values(...)
           .execute();
}

问题答案:

由于死锁发生的频率很高,因此应用程序的某些线程似乎长时间持有锁。

应用程序中的每个线程在访问数据库时都会使用其自己的一个数据库连接/一个连接,因此从数据库的角度来看,两个线程是争夺数据库锁的两个不同的客户端。

如果一个线程长时间持有锁并以一定顺序获取它们,而第二个线程随即获得了相同的锁却以不同的顺序获取,则肯定会发生死锁

读操作中也会发生死锁,这意味着某些线程也正在获取读锁。如果线程在REPEATABLE_READ隔离级别或级别运行事务,则会发生这种情况SERIALIZABLE

为了解决这个问题,尝试搜索的用途Isolation.REPEATABLE_READIsolation.SERIALIZABLE项目,来看看这被使用。

或者,使用默认READ_COMMITTED隔离级别,并使用注释实体@Version,以使用乐观锁定来处理并发。

还要尝试识别长时间运行的事务,有时会发生这种情况,因为@Transactional将它们放置在错误的位置并在批处理示例中包装了整个文件的处理,而不是逐行进行事务。

这是一个log4j配置,用于记录实体管理器的创建/删除和事务开始/提交/回滚:

   <!-- spring entity manager and transactions -->
<logger name="org.springframework.orm.jpa" additivity ="false">
    <level value="debug" />
    <appender-ref ref="ConsoleAppender" />
</logger >
<logger name="org.springframework.transaction" additivity ="false">
    <level value="debug" />
    <appender-ref ref="ConsoleAppender" />
</logger >
  1. 我可以以某种方式执行更新查询(JPA / Native)而不必通过@Transactional锁定表吗?

可以通过本机查询或JPQL进行更新查询。

  1. 我可以不使用@Transactional进入会话吗? 例如,预定线程尝试将Entity上的Lazy字段读取为LazyInitializationException-如果没有使用@Transactional注释方法,则没有会话

在没有的方法中@Transactional,查询将在其自己的实体管理器中执行,并且仅返回分离的实体,因为在运行查询后会立即关闭会话。

因此,没有这种方法的方法中的延迟初始化异常@Transactional是正常的。您也可以将它们设置@Transactional(readOnly=true)为。



 类似资料:
  • 表以作为主键,列(CHAR(1))可以是“x”或“y”,以及(INT)。这些列上没有索引。存储引擎是InnoDB。 state_positions必须总是连续的,并且对于某个状态可能永远不会有重复的位置,即如果我有5个状态为“x”的用户,他们的state_positions必须是1、2、3、4、5 这是我正在运行的导致死锁的查询: 为了测试,我同时插入了大量的用户,但每次都出现死锁错误。 我读了这

  • 我得到以下错误当有多个更新运行特定的表数据库-mysql-innodb引擎语言php-pdo 错误-序列化失败:尝试获取锁时发现死锁 我检查了下面的链接SQLState[40001]:序列化失败:尝试获取锁时发现1213死锁;尝试按Magento位置重新启动事务

  • 问题内容: 我的应用程序(java spring-core)有多个线程同时运行并访问数据库,在某些高峰时间出现异常 我的代码看起来 问题答案: MySQL的InnoDB引擎具有行级锁定功能,即使您的代码正在插入或更新单个行(尤其是要更新的表上有多个索引),也可能导致死锁。最好的选择是围绕它设计代码,以便在由于死锁而失败的情况下重试事务。一些有关MySQL死锁诊断的有用信息以及可能的解决方法在此处提

  • 问题内容: 我有一个带有约5,000,000行的MySQL表,该表通过通过DBI连接的并行Perl进程以小方式不断更新。该表有大约10列和几个索引。 一种相当常见的操作有时会导致以下错误: 触发错误的SQL语句如下所示: 该错误仅在某些时候触发。我估计会减少1%的来电。但是,使用小表从未发生这种情况,随着数据库的增长,它变得越来越普遍。 请注意,我正在使用file_table中的a_lock字段来

  • 问题内容: 我有一个记录在线用户的innoDB表。用户每次刷新页面时都会对其进行更新,以跟踪他们所访问的页面以及它们对该站点的最后访问日期。然后,我会有一个cron,每15分钟运行一次,以删除旧记录。 我在尝试获取锁时发现了“死锁;昨晚尝试重新启动事务”大约5分钟,这似乎是在向该表中运行INSERT时出现的情况。有人可以建议如何避免此错误吗? ===编辑=== 以下是正在运行的查询: 首次访问网站

  • 问题内容: 我有一个客户端服务器应用程序,并且在我的服务器中,我正在使用hibernate模式进行数据库处理。现在,我的应用程序需要所有数据库表中的一个简单表,其中仅一个行包含一个字段(这是该行的键)。该表实际上仅包含一个全局编号(从1开始),我在用户每次执行某些操作时都会使用该编号,当他执行此操作时,我需要获取该值并在数据库中递增该值。(表应该只包含一行,并且始终只有一个值) 我正在使用以下代码