我遇到了一个 Spring Boot 应用程序的奇怪问题。
详细信息在这里:
该应用程序有一个 spring 批处理作业,它使用 JpaItemWriter 执行对数据库的写入。
此外,应用程序配置为使用 hibernate
ItemWriter配置如下:
@Bean(name = "itemWriter")
@StepScope
public ItemWriter<Record> itemWriter() {
JpaItemWriter<Record> itemWriter = new JpaItemWriter<>();
itemWriter.setEntityManagerFactory(emf);
return itemWriter;
}
批处理作业过去工作得很好,但最近我们将 Jenkins 升级到了 Jenkins(2.73.3)。之后,使用这个新的 Jenkins 构建和部署代码 运行相同的批处理作业时开始引发以下错误:
2017-12-03 16:09:44.720 DEBUG - testservice - - jobLauncher-3 - org.springframework.batch.item.database.JpaItemWriter:97 - Writing to JPA with 4 items.
2017-12-03 16:09:44.733 DEBUG - testservice - - jobLauncher-3 - org.springframework.batch.item.database.JpaItemWriter:109 - 4 entities merged.
2017-12-03 16:09:44.733 DEBUG - testservice - - jobLauncher-3 - org.springframework.batch.item.database.JpaItemWriter:110 - 0 entities found in persistence context.
2017-12-03 16:09:44.743 WARN - testservice - - jobLauncher-3 - com.shared.domain.error.BatchExceptionHandler:63 - [test-service]999999999(Dn9lM4c)ExhaustedRetryException: Unable to locate ErrorDetail for Id ExhaustedRetryException. Details:
org.springframework.retry.ExhaustedRetryException: Retry exhausted after last attempt in recovery path, but exception is not skippable.; nested exception is javax.persistence.TransactionRequiredException: no transaction is in progress
at org.springframework.batch.core.step.item.FaultTolerantChunkProcessor$5.recover(FaultTolerantChunkProcessor.java:403) ~[spring-batch-core-3.0.7.RELEASE.jar!/:3.0.7.RELEASE]
at org.springframework.retry.support.RetryTemplate.handleRetryExhausted(RetryTemplate.java:473) ~[spring-retry-1.1.5.RELEASE.jar!/:?]
at org.springframework.retry.support.RetryTemplate.doExecute(RetryTemplate.java:333) ~[spring-retry-1.1.5.RELEASE.jar!/:?]
at org.springframework.retry.support.RetryTemplate.execute(RetryTemplate.java:201) ~[spring-retry-1.1.5.RELEASE.jar!/:?]
使用旧 Jenkins(Jenkins 版本 1.646)构建和部署相同的代码库时,工作正常。
在这两种情况下,应用程序都部署在具有相同 AMI 的 EC2 实例 (AWS) 上。因此它们运行的服务器没有区别。
此外,我检查了两个版本的 Jenkins 上用于构建代码的 Java 版本和 maven 版本,它们是相同的。
Maven版本和Java版本:
Apache Maven 3.0.4 (r1232337; 2012-01-17 08:44:56+0000)
Maven home: /opt/maven/apache-maven-3.0.4
Java version: 1.8.0_72, vendor: Oracle Corporation
Java home: /usr/java/jdk1.8.0_72/jre
Default locale: en_US, platform encoding: UTF-8
其他版本:
SpringBoot: 1.4.7.RELEASE
HibernateVersion: 5.2.3.Final
唯一的区别是旧版 Jenkins 运行在 AWS RHEL 上,而新版 Jenkins 运行在 CentOS7 上。
我什至检查了这两种情况下创建的 jar ,似乎没有什么不同。
目前不确定如何进一步解决此问题
已编辑:
我对两个 Jenkins 生成的代码进行了远程调试,以下是所做的观察。
JpaItemWriter 调用“EntityManagerFactoryUtils.getTransactionalEntityManager”并在方法中 “emHolder”在一种情况下为空,在另一种情况下具有有效值。
public static EntityManager doGetTransactionalEntityManager(
EntityManagerFactory emf, Map<?, ?> properties, boolean synchronizedWithTransaction) throws PersistenceException {
Assert.notNull(emf, "No EntityManagerFactory specified");
EntityManagerHolder emHolder =
(EntityManagerHolder) TransactionSynchronizationManager.getResource(emf);
// This line returns a valid emHolder
// But in case of the code which is not working, it is returning a
// null value
EntityManagerHolder emHolder =
(EntityManagerHolder) TransactionSynchronizationManager.getResource(emf);
不确定为什么 NamedThreadLocal>("Transactional resources") 在一种情况下没有entityMangerHolder,而在另一种情况下则没有。
更新
经过更多调试,我发现代码不起作用 spring 批处理作业使用“DataSourceTransactionManager”,但在其他情况下它使用 JpaTransactionManager。
最佳答案
我现在能够解决我的问题,以下是我的发现:
这两种情况下创建 Bean 的顺序似乎有所不同。
我在配置类中定义了一个 JpaTransaction 管理器 bean。这个 bean 从来都不是使用 Jenkins 2.0 生成的代码创建的。
Spring 正在“org.springframework.batch.core.configuration.annotation.SimpleBatchConfiguration”类中生成代理事务管理器 bean,并且此事务管理器不能与 JpaItemWriter 很好地配合。
我看到了一张 JIRA 票证,其中讨论了 SimpleBatchConfiguration 的问题。
https://jira.spring.io/browse/BATCH-2294
在我的 BatchConfiguration 类中添加相同的 JpaTransaction bean 后, 问题消失了。
关于hibernate - 交易所需异常 : no transaction is in progress while using JPAItemWriter,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47622387/