我在使用 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(使用前将#替换为@)