TransactionRequiredException:使用JPAItemWriter时没有事务正在进行中

Pra*_*r D 7 hibernate spring-batch spring-data spring-data-jpa spring-boot

我面临一个奇怪的问题,一个应用程序是一个弹簧启动应用程序.

细节在这里:

该应用程序有一个弹簧批处理作业,它使用JpaItemWriter执行对数据库的写入.

此外,应用程序配置为使用休眠

ItemWriter配置如下:

 @Bean(name = "itemWriter")
  @StepScope
  public ItemWriter<Record> itemWriter() {
      JpaItemWriter<Record> itemWriter = new JpaItemWriter<>();
      itemWriter.setEntityManagerFactory(emf);
      return itemWriter;
  }
Run Code Online (Sandbox Code Playgroud)

批量工作过去很好,但最近我们将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!/:?]
Run Code Online (Sandbox Code Playgroud)

使用Old Jenkins(Jenkins ver.1.664)构建和部署相同的代码库时,工作正常.

在这两种情况下,应用程序都部署在具有相同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
Run Code Online (Sandbox Code Playgroud)

其他版本:

SpringBoot: 1.4.7.RELEASE
HibernateVersion: 5.2.3.Final
Run Code Online (Sandbox Code Playgroud)

唯一的区别是旧的Jenkins在AWS RHEL上运行,而新的Jenkins在CentOS7上运行.

我甚至检查了两个案例中创建的罐子,似乎没有什么不同.

目前还不确定如何进一步解决此问题

编辑:

我对Jenkins生成的代码进行了远程调试,以下是观察结果.

JpaItemWriter调用"EntityManagerFactoryUtils.getTransactionalEntityManager",并且方法"emHolder"在一种情况下为null,在另一种情况下具有有效值.

    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);
Run Code Online (Sandbox Code Playgroud)

不确定为什么NamedThreadLocal>("Transactional resources")在一种情况下没有entityMangerHolder但在其他情况下没有.

更新

在进行更多调试后,我发现的代码是无效的代码弹簧批处理作业使用"DataSourceTransactionManager"但在其他情况下它使用JpaTransactionManager.

Pra*_*r D 2

我现在能够解决我的问题,以下是我的发现:

似乎这两种情况下创建 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 后,问题就消失了。