打开新的EntityManager后进行线程锁定

时间:2014-06-27 06:54:32

标签: 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");

        ...
    }
}

看一下日志文件,我发现从log"调用加密方法"需要16分钟。 to" encripting"。所以,已经激活了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代码的其他点调用A类的其他方法没有问题。
  • 刚刚在生产环境中发生。你可以想象做出改变是多么困难。
  • 数据库连接通过JNDI到MySql完成,应用程序在Tomcat中运行。

我知道有了这些信息很难找出问题所在。我希望有人可以提供一些帮助我找到正在发生的事情的想法。

1 个答案:

答案 0 :(得分:1)

对我而言,这听起来非常像this SO question

使用REQUIRES_NEW将始终确保新的交易,因此如果已存在应该暂停的交易。

但由于JPATransactionManager不支持嵌套交易:

  

在JDBC 3.0上,此事务管理器支持嵌套事务   JDBC 3.0保存点。该   AbstractPlatformTransactionManager.setNestedTransactionAllowed(布尔)   但是,“nestedTransactionAllowed”}标志默认为“false”   嵌套事务只适用于JDBC连接,而不适用于   JPA EntityManager及其缓存对象。你可以手动设置   如果要使用嵌套事务进行JDBC访问,则标记为“true”   参与JPA事务的代码(假设您的JDBC   驱动程序支持保存点)。请注意,JPA本身不支持   嵌套交易!因此,不要指望JPA访问代码   语义上参与嵌套事务。

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