2014-06-27 44 views
1

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

这里的情况是:

@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分钟内由日志“呼吁加密方法”,以“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 [[email protected]] 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 [[email protected]] 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 [[email protected]] 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 [[email protected]] for JPA transaction 

... 

15:24:29.954 DEBUG o.s.orm.jpa.JpaTransactionManager [408] - Not exposing JPA transaction [[email protected]] as JDBC transaction because JpaDialect [[email protected]] 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 [[email protected]] 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 [[email protected]] 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 [[email protected]] 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中运行。

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

回答

1

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

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

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

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

所以这两个事务将共享相同的JDBC连接,并且可能会涉及一些锁定。是否事务超时设置为15分钟,这就是为什么你会看到它在这段时间内停滞不前?

+0

感谢您的贡献。没有定义事务超时,所以我们正在使用默认值(-1)。另外,认为它不能解释为什么它不会总是发生。我必须找出16个来自哪里,我认为这是关键。 – jddsantaella

+0

它是否复制,而不是需要新的您需要? –

+0

我没有测试它。我们正在一个PCI-DSS生产环境中工作,因此修改变得非常复杂。我所做的是在课堂级别移除交易,并仅在需要的方法中对其进行定义。由于“加密”方法不需要交易,所以希望我们不要再次面对错误。让我们来看看。我会尝试在其他环境中重现错误(如果我很幸运)并测试您的想法。 – jddsantaella