java - 打开新的 EntityManager 后线程锁

标签 java spring hibernate jpa transactions

我在使用 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 中运行。

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

最佳答案

对我来说,这听起来很像 this SO question .

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

但由于 JPATransactionManager 不支持嵌套事务:

On JDBC 3.0, this transaction manager supports nested transactions via JDBC 3.0 Savepoints. The AbstractPlatformTransactionManager.setNestedTransactionAllowed(boolean) "nestedTransactionAllowed"} flag defaults to "false", though, as nested transactions will just apply to the JDBC Connection, not to the JPA EntityManager and its cached objects. You can manually set the flag to "true" if you want to use nested transactions for JDBC access code which participates in JPA transactions (provided that your JDBC driver supports Savepoints). Note that JPA itself does not support nested transactions! Hence, do not expect JPA access code to semantically participate in a nested transaction.

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

关于java - 打开新的 EntityManager 后线程锁,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24445721/

相关文章:

java - hibernate中复合键的Where子句

java - 如何使用 Spring "matches"方法检查旧密码?

spring - 如何在 AWS ElasticBeanstalk 和 Nginx 上使用 OAuth2 的 Spring Boot 应用程序上强制使用 SSL?

java - EJB 访问有状态 session Bean NameNotFoundException

java - spring mvc herbinate 与额外列的多对多关系存在问题

java - RJB Hello World 示例

java - Map Reduce IOException中的问题

java - hibernate 5 : db connections are still not released (idle in transaction) after lazy loading

java - 如何发出 Spring RestTemplate PATCH 请求

java - Hibernate HQL注入(inject)示例