打开新EntityManager后线程锁

2024-05-20

我在使用 Spring JPA 事务时遇到一个非常奇怪的错误。该线程被锁定大约 16 分钟,然后继续,没有任何问题。

情况如下:

@Transactional(propagation = Propagation.REQUIRES_NEW)
public class A {

    public String encrypt(String str){

        LOG.debug("encrypting...");

        // just data base read operations

    }

    public String encrypt(String str, String str2){

        // read and write database operations.

    }    

    public String foo(...){

        // read and write database operations.

    }

    public String bar(...){

        // read and write database operations.

    }
}

@Transactional(propagation = Propagation.REQUIRES_NEW)
public class B {

    public String doSomething(...){

        LOG.debug("calling encrypt method...");

        String chain1 = this.a.encrypt("whatever");

        LOG.debug("calling encrypt method...");

        String chain2 = this.a.encrypt("again");

        LOG.debug("calling encrypt method...");

        String chain3 = this.a.encrypt("and again");

        ...
    }
}

查看日志文件,我发现从日志“调用加密方法”到“加密”需要 16 分钟。因此,已激活 JTA 日志,这就是我所看到的:

15:09:04.317 DEBUG e.i.n.p.d.TipoMensajeDaoDelegate [45] - obteniendo mensaje para tipo operacion 0104 y protocolo 03
15:09:04.318 DEBUG o.s.orm.jpa.JpaTransactionManager [332] - Found thread-bound EntityManager [org.hibernate.ejb.EntityManagerImpl@4e6b01e9] for JPA transaction
15:09:04.319 DEBUG o.s.orm.jpa.JpaTransactionManager [471] - Participating in existing transaction
15:09:04.320 DEBUG o.s.orm.jpa.JpaTransactionManager [332] - Found thread-bound EntityManager [org.hibernate.ejb.EntityManagerImpl@4e6b01e9] for JPA transaction
15:09:04.321 DEBUG o.s.orm.jpa.JpaTransactionManager [471] - Participating in existing transaction
15:09:04.324 DEBUG e.i.n.c.p.p.b.B [485] - calling encrypt method...
15:09:04.325 DEBUG o.s.orm.jpa.JpaTransactionManager [332] - Found thread-bound EntityManager [org.hibernate.ejb.EntityManagerImpl@4e6b01e9] for JPA transaction
15:09:04.326 DEBUG o.s.orm.jpa.JpaTransactionManager [416] - Suspending current transaction, creating new transaction with name [es.indra.nnp.gestorclaves.GestorClavesServiceImpl.cifrar]
15:09:04.326 DEBUG o.s.orm.jpa.JpaTransactionManager [369] - Opened new EntityManager [org.hibernate.ejb.EntityManagerImpl@27f2b012] for JPA transaction

...

15:24:29.954 DEBUG o.s.orm.jpa.JpaTransactionManager [408] - Not exposing JPA transaction [org.hibernate.ejb.EntityManagerImpl@27f2b012] as JDBC transaction because JpaDialect [org.springframework.orm.jpa.DefaultJpaDialect@4d832b01] does not support JDBC Connection retrieval
15:24:29.955 DEBUG e.i.n.g.A [146] - encrypting
15:24:29.956 DEBUG o.s.orm.jpa.JpaTransactionManager [332] - Found thread-bound EntityManager [org.hibernate.ejb.EntityManagerImpl@27f2b012] for JPA transaction
15:24:29.957 DEBUG o.s.orm.jpa.JpaTransactionManager [471] - Participating in existing transaction
15:24:29.958 DEBUG o.s.orm.jpa.JpaTransactionManager [332] - Found thread-bound EntityManager [org.hibernate.ejb.EntityManagerImpl@27f2b012] for JPA transaction
15:24:29.958 DEBUG o.s.orm.jpa.JpaTransactionManager [471] - Participating in existing transaction
15:24:29.962 DEBUG o.s.orm.jpa.JpaTransactionManager [332] - Found thread-bound EntityManager [org.hibernate.ejb.EntityManagerImpl@27f2b012] for JPA transaction
15:24:29.962 DEBUG o.s.orm.jpa.JpaTransactionManager [471] - Participating in existing transaction
...

在此,事实如下:

  • 错误并不总是发生,但当它发生时,它总是发生在同一点。
  • 大约 16 分钟后,线程继续并调用相同的方法几次,没有任何问题并正确完成。
  • 当它发生时,总是在15分30秒左右。
  • 它是在没有并发的情况下发生的。无论如何,当一个线程被锁定时,如果我启动另一个线程是没有问题的。当第一个线程仍处于锁定状态时,将处理第二个线程。
  • 在锁定发生时,已检查 DDBB 以查找数据库锁定。未发现数据库锁。
  • 从代码的其他点调用 A 类的其他方法没有问题。
  • 仅发生在生产环境中。你可以想象做出改变是多么困难。
  • 数据库连接是通过 JNDI 完成到 MySql 的,应用程序在 Tomcat 中运行。

我知道凭这些信息很难找出问题出在哪里。我只是希望有人能提出一些想法,帮助我找到正在发生的事情。


对我来说这听起来很像这个问题 https://stackoverflow.com/questions/10736862/jpa-nested-transactions-and-locking.

使用 REQUIRES_NEW 将始终确保新的事务,因此如果已经存在应暂停的事务。

但由于嵌套事务不支持JPA事务管理器 http://docs.spring.io/spring/docs/2.0.x/api/org/springframework/orm/jpa/JpaTransactionManager.html:

在 JDBC 3.0 上,该事务管理器通过以下方式支持嵌套事务 JDBC 3.0 保存点。这 AbstractPlatformTransactionManager.setNestedTransactionAllowed(boolean) 不过,“nestedTransactionAllowed”}标志默认为“false”,如下所示 嵌套事务仅适用于 JDBC 连接,而不适用于 JPA EntityManager 及其缓存对象。您可以手动设置 如果您想使用嵌套事务进行 JDBC 访问,则标记为“true” 参与 JPA 事务的代码(前提是您的 JDBC 驱动程序支持保存点)。注意JPA本身不支持 嵌套事务!因此,不要期望 JPA 访问代码 在语义上参与嵌套事务。

因此,两个事务将共享相同的 JDBC 连接,并且可能涉及一些锁定。事务超时是否设置为 15 分钟,这就是您看到它挂起这么长时间的原因?

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

打开新EntityManager后线程锁 的相关文章

随机推荐