Hibernate:尝试获取锁定时发现死锁 [英] Hibernate: Deadlock found when trying to obtain lock

查看:107
本文介绍了Hibernate:尝试获取锁定时发现死锁的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述



有一个Stack Traces: 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();

$ / code>

我很困难,因为我不知道它是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>已停用< / prop>
<! - 使用C3P0连接池提供程序 - >
< 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>

EDIT1:


  • 我在上面写到有明显的死锁发生 - 这是错误的,只有尝试获取锁定时发现死锁发生。


EDIT2:



在这些方法上也会发生这种情况 - 这些需要用@Transactional注释:

<$ p $ ()
.values(...)
.execute(())
$ b公共无效setLastActivity(){
em.insertNative(table );

$ / code>


解决方案

,它看起来像应用程序的一些线程长时间持有锁。

应用程序中的每个线程在访问数据库时都会使用它自己的数据库连接/连接,所以从数据库的角度来看,两个线程是两个不同的客户端对于数据库锁。



如果一个线程长时间持有锁并以特定顺序获取它们,并且第二个线程获得相同的锁,一个不同的顺序,必然会发生死锁(请参阅此处获取有关此频繁死锁的详细信息原因)。

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



为了解决这个问题,请尝试搜索 Isolation.REPEATABLE_READ Isolation.SERIALIZABLE 的用法。项目,看看这是否被使用。作为一种替代方法,使用默认的 READ_COMMITTED 隔离级别,并使用 @注释实体 版本,使用

另外,尝试识别长时间运行的交易,有时会发生这种情况,当 @Transactional 被放置在错误的地方,例如在批处理的例子中包含整个文件的处理,而不是逐行进行处理。

 < p>< p> ! - 春季实体经理和交易 - > 
< logger name =org.springframework.orm.jpaadditivity =false>
< level value =debug/>
< appender-ref ref =ConsoleAppender/>
< / logger>
< logger name =org.springframework.transactionadditivity =false>
< level value =debug/>
< appender-ref ref =ConsoleAppender/>
< / logger>




  1. 我能以某种方式执行更新查询(JPA / Native )而不必通过@Transactional锁定表



  2. 更新查询可以通过本机查询或JPQL


    1. 我可以以某种方式进入会话而不使用@Transactional吗? 例如,调度的线程试图读取实体中的Lazy字段产生LazyInitializationException - 没有会话,如果方法不是用@Transactional注释

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



    所以方法中的懒惰初始化异常 @Transactional 是正常的。您可以将它们设置为 @Transactional(readOnly = true)


    I am using hibernate in my project and I am getting random Apparent Deadlocks for very simple database operations.

    There is one of the Stack Traces: https://gist.github.com/knyttl/8999006 – What confuses me, that the first Exception is RollbackException and then there are LockAquisition Exceptions.

    The problem happens often on similar clauses:

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

    I am quite stuck as I don't know whether it is problem of Hibernate, MySQL or C3P0.

    My Hibernate configuration:

                <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>
    

    EDIT1:

    • I wrote above there were Apparent Deadlocks happening - that was wrong, only "Deadlock found when trying to obtain lock" happen.

    EDIT2:

    This happens also on these methods - those NEEDS to be annotated with @Transactional:

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

    解决方案

    Because the deadlocks happen so frequently, it looks like some of the threads of the application are holding locks for an extended period of time.

    Each thread in the application will use it's own database connection/connections while accessing the database, so from the point of view of the database two threads are two distinct clients that compete for database locks.

    If a thread holds locks for an extended period of time and acquires them in a certain order, and a second thread comes along acquiring the same locks but on a different order, deadlock is bound to occur (see here for details on this frequent deadlock cause).

    Also deadlocks are occurring in read operations, which means that some threads are acquiring read locks as well. This happens if the threads are running transactions in REPEATABLE_READ isolation level or SERIALIZABLE.

    To solve this, try searching for usages of Isolation.REPEATABLE_READ and Isolation.SERIALIZABLEin the project, to see if this is being used.

    As an alternative, use the default READ_COMMITTED isolation level and annotate the entities with @Version, to handle concurrency using optimistic locking instead.

    Also try to identify long running transactions, this happens sometimes when the @Transactional is placed at the wrong place and wraps for example the processing of a whole file in the example of a batch processing, instead of doing transactions line by line.

    This a log4j configuration to log the creation/deletion of entity managers and transactions begin/commit/rollback:

       <!-- 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. Can I somehow execute update query (either JPA/Native) without having to lock the table via @Transactional?

    Update queries are possible via native queries or JPQL.

    1. Can I somehow get into session without using @Transactional? For instance, scheduled thread tries to read Lazy field on Entity yields to LazyInitializationException - no session, if the method is not annotated with @Transactional

    In methods without @Transactional, queries will be executed in it's own entity manager and return only detached entities, as thee session is closed immediatelly after the query is run.

    so the lazy initialization exceptions in methods without @Transactional is normal. You can set them to @Transactional(readOnly=true) as well.

    这篇关于Hibernate:尝试获取锁定时发现死锁的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆