JpaPagingItemReader - бесконечный цикл при неудачном чтении

Привет, я получаю бесконечный цикл при возникновении исключения. Что-то не так с менеджером транзакций, который я использую? Спасибо! Ниже представлены мои настройки работы

@Bean
public ItemReader<Entity> bizAppReader() {
    @SuppressWarnings("serial")
    Map<String, Object> map  = new HashMap<String, Object>() {{
      put("status", Arrays.asList(new ApplicationStatus[] {ApplicationStatus.COMPLETED, ApplicationStatus.PENDING, ApplicationStatus.INITIATE}));
    }};

    return new JpaPagingItemReaderBuilder<Entity>()
        .name("bizAppJpaReader")
        .entityManagerFactory(entityManagerFactory)
        .queryString("from Entity b where b.status in (:status)").parameterValues(map)
        .build();
  }

@Bean
public Step bizApplicatonStep(@Value("${batch.chunk_size:10}") int chunkSize,
      ItemReader<Entity> bizAppReader,
      ItemProcessor<Entity, Map<ApplicationStatus, String>> bizAppProcessor,
      ItemWriter<Map<ApplicationStatus, String>> bizAppWriter) {

    return stepBuilderFactory.get("bizApplicatonStep")
        .<Entity, Map<ApplicationStatus, String>>chunk(chunkSize).reader(bizAppReader)
        .processor(bizAppProcessor).writer(bizAppWriter)
        .faultTolerant()
          .skip(Exception.class)
          .noRollback(Exception.class)
          .skipPolicy((e, i) -> {
            log.error("Exception occurred : ", e);

            return true;
            })
          .allowStartIfComplete(true)
      .build();
  }

@Slf4j
@SpringBootApplication
@EnableBatchProcessing
public class BatchApplication  extends DefaultBatchConfigurer {

  public static void main(String[] args) throws Exception {

    ConfigurableApplicationContext context = SpringApplication.run(BatchApplication.class, args);

    JobLauncher jobLauncher = context.getBean(JobLauncher.class);
    Job job;
    JobParameters jobParameters;

    if (ArrayUtils.isNotEmpty(args) && args[0].equals("bookingJob")) {
      job = context.getBean("bookingJob", Job.class);
      jobParameters = new JobParametersBuilder()
        .addString("startMonth", args[1])
        .addString("endMonth", args[2])
        .toJobParameters();
    } else {
      job = context.getBean("bizApplicationJob", Job.class);
      jobParameters = new JobParametersBuilder().toJobParameters();
    }
    JobExecution jobExecution = jobLauncher.run(job, jobParameters);

    if (BatchStatus.FAILED.equals(jobExecution.getStatus())) {
      log.error("job execution completed exit code is : 1 ");
      System.exit(1);
    }
    log.info("job execution completed exit code is : 0 ");
  }

  @Override
  protected JobRepository createJobRepository() throws Exception {
    return new MapJobRepositoryFactoryBean(new ResourcelessTransactionManager()).getObject();
  }
}

Трассировки стека:

10:13:20.657 [main] ERROR c.u.pweb.bizacct.batch.BizJobConfig - Exception occurred : 
java.lang.IllegalStateException: Transaction already active
   at org.hibernate.engine.transaction.internal.TransactionImpl.begin(TransactionImpl.java:52)

- ===================== Обновлено приложение для репликации =====================

это происходит, если читателю не удалось прочитать из БД с недопустимым значением Enum.

@Slf4j
@SpringBootApplication
@EnableBatchProcessing
public class DemoBatchApplication extends DefaultBatchConfigurer {

    public static void main(String[] args) {
        SpringApplication.run(DemoBatchApplication.class, args);
    }

    @Override
    public void setDataSource(DataSource dataSource) {
        super.setDataSource(null);
    }

    private final EntityManagerFactory entityManagerFactory;

  public DemoBatchApplication(EntityManagerFactory entityManagerFactory) {
    this.entityManagerFactory = entityManagerFactory;
  }

    @Override
  public PlatformTransactionManager getTransactionManager() {
    return new JpaTransactionManager(this.entityManagerFactory);
  }

}

перечислить

public enum ApplicationStatus {
  MA, AS, SH, CP, AA, AP
}

Таблица

@Entity
@Table(name = "APP_TBL_TEST")
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class ApplicationEntity {

  @Id
  @GeneratedValue(generator = "system-uuid")
  @GenericGenerator(name = "system-uuid", strategy = "uuid2")
  @Column(name = "ID", length = 50)
  private String id;

  @Column(name = "APPLICATION_NAME", unique = true, length = 50)
  private String referenceNumber;

  @Column(name = "STATUS")
  @Enumerated(EnumType.STRING)
  private ApplicationStatus status;

}

пакетная конфигурация

@Configuration
@Slf4j
@Data
public class ApplicationBatchCfg {

  @Autowired
  public EntityManagerFactory entityManagerFactory;
  @Autowired
  public JobBuilderFactory jobBuilderFactory;
  @Autowired
  public StepBuilderFactory stepBuilderFactory;

  @Bean
  public Step applicationStep(@Value("${batch.chunk_size:5}") int chunkSize,
                              ItemReader<ApplicationEntity> appReader,
                              ItemProcessor<ApplicationEntity, String> appProcessor,
                              ItemWriter<String> appWriter){

    return stepBuilderFactory.get("applicatonStep")
      .<ApplicationEntity, String>chunk(chunkSize)
      .reader(appReader)
      .processor(appProcessor)
      .writer(appWriter)
      .faultTolerant()
      .skip(Exception.class)
      .noRollback(Exception.class)
      .skipPolicy((e, i) -> {
        log.error("Exception occurred : ", e);

        return true;
      })
      .skipLimit(5)
      .allowStartIfComplete(true)
      .build();

  }

  @Bean
  public Job applicationJob(Step applicationStep) {
    return jobBuilderFactory.get("applicationJob").incrementer(new RunIdIncrementer())
      .start(applicationStep).build();
  }

  @Bean
  public ItemReader<ApplicationEntity> appReader() {
    return new JpaPagingItemReaderBuilder<ApplicationEntity>()
      .name("appReader")
      .entityManagerFactory(entityManagerFactory)
      .queryString("from ApplicationEntity")
      .pageSize(3)
      .build();
  }

  @Bean
  public ItemProcessor<ApplicationEntity, String> appProcessor(){
    return new ItemProcessor<ApplicationEntity, String>() {
      @Override
      public String process(ApplicationEntity item) throws Exception {
        //nothing for demo only
        log.info("item {}", item);
        return null;
      }
    };
  }

  @Bean
  public ItemWriter<String> appWriter() {
    return new ItemWriter<String>() {
      @Override
      public void write(List<? extends String> items) throws Exception {
        //nothing for demo only
      }
    };
  }

}

внутри yml

spring:
  jpa:
     properties:
       hibernate:
         show_sql: true
         use_sql_comments : true
         format_sql: true
         dialect: org.hibernate.dialect.Oracle10gDialect
  datasource:
    useWallet: false
    url: jdbc:oracle:thin:@DB12397:1521:azd
    platform: oracle
    username: user
    password: pwd

Я не могу дать точный ответ, не воспроизводя проблему. Что касается вашего вопроса о диспетчере транзакций, вам необходимо использовать JpaTransactionManager, поскольку вы используете JPA.

Mahmoud Ben Hassine 06.12.2018 15:27

@MahmoudBenHassine Спасибо за ваш ответ, я обновил свой пост, чтобы его можно было воспроизвести. Я надеюсь, что вы сможете реплицировать на своем локальном компьютере .. Он запускает бесконечный цикл, если не может прочитать недопустимое значение Enum из базы данных.

Lp. Don 07.12.2018 06:55

Запустите приложение с флагом --debug и приложите полный журнал с полной трассировкой стека. Невозможно воспроизвести проблему с тем, чем вы поделились (отсутствуют зависимости в pom.xml или build.gradle, импорт, нужен Oracle db ..), поэтому, пожалуйста, поделитесь MVCE со встроенным db на github / gitlab, и я возьму взгляд.

Mahmoud Ben Hassine 07.12.2018 09:13
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Версия Java на основе версии загрузки
Версия Java на основе версии загрузки
Если вы зайдете на официальный сайт Spring Boot , там представлен start.spring.io , который упрощает создание проектов Spring Boot, как показано ниже.
Документирование API с помощью Swagger на Springboot
Документирование API с помощью Swagger на Springboot
В предыдущей статье мы уже узнали, как создать Rest API с помощью Springboot и MySql .
0
3
325
0

Другие вопросы по теме