【问题标题】:TransactionRequiredException: no transaction is in progress while using JPAItemWriterTransactionRequiredException:使用 JPAItemWriter 时没有正在进行的事务
【发布时间】:2018-05-17 06:29:42
【问题描述】:

我在使用 Spring Boot 应用程序时遇到了奇怪的问题。

详情在此:

该应用有一个 spring 批处理作业,它使用 JpaItemWriter 执行对数据库的写入。

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

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 上运行,而新的在 CentOS7 上运行。

我什至检查了这两种情况下创建的罐子,似乎没有什么不同。

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

已编辑

我对 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。

【问题讨论】:

  • 对生成的人工制品进行比较。
  • @JensSchauder 我用超越比较做了一个差异,除了版本号没有什么不同
  • 你是在生成一个胖罐子,还是一场战争?您确定 Jenkins 在两个地方都引入了相同的依赖项吗?您是否在 poms 中指定了依赖项的确切版本?如果不是,则构建可能包含不同版本的依赖项。
  • @PaulNUK 我们正在使用一个胖 jar。Jenkins 在这两种情况下都在提取依赖项,我们正在为依赖项指定确切的版本。我确实比较了两个罐子的内容,它们完全一样。(我用超越比较来做字节比较)
  • 如果有助于澄清,我们解压缩 JAR 并发现没有显着差异。但是,当在 Beyond Compare 中对 JAR 本身进行比较时,最初在 HEX 代码中似乎确实存在差异。

标签: hibernate spring-boot spring-data spring-data-jpa spring-batch


【解决方案1】:

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

似乎在这两种情况下创建 bean 的顺序有所不同。

我在我的配置类中定义了一个 JpaTransaction 管理器 bean。这个 bean 从未使用使用 Jenkins 2.0 生成的代码创建。

Spring 正在“org.springframework.batch.core.configuration.annotation.SimpleBatchConfiguration”类中生成一个代理事务管理器 bean,而这个事务管理器不能与 JpaItemWriter 一起工作。

我看到了一个讨论 SimpleBatchConfiguration 问题的 JIRA 票证。

https://jira.spring.io/browse/BATCH-2294

在我的 BatchConfiguration 类中添加相同的 JpaTransaction bean 后, 问题消失了。

【讨论】:

    猜你喜欢
    • 2014-04-25
    • 2016-10-17
    • 2013-03-23
    • 1970-01-01
    • 2020-09-10
    • 2014-05-31
    • 2015-11-24
    • 2012-07-29
    • 1970-01-01
    相关资源
    最近更新 更多