当前位置: 首页 > 知识库问答 >
问题:

Spring Batch 内存泄漏 - 使用 JpaItemWriter 将 CSV 到数据库

田硕
2023-03-14

我在使用Spring批处理作业读取大型CSV文件(几百万条记录)并将其中的记录保存到数据库时遇到了问题。该作业使用< code>FlatFileItemReader来读取CSV,并使用< code>JpaItemWriter将读取和处理的记录写入数据库。问题是< code>JpaItemWriter在将另一个项目块刷新到数据库后没有清除持久性上下文,作业以< code>OutOfMemoryError结束。

我已经通过扩展JpaItemWriter并覆盖写入方法解决了这个问题,以便在编写一堆之后调用EntityManager.clear(),但是我想知道Spring Batch是否已经解决了这个问题,并且问题的根源在于作业配置。如何以正确的方式解决此问题?

我的解决方案:

class ClearingJpaItemWriter<T> extends JpaItemWriter<T> {

        private EntityManagerFactory entityManagerFactory;

        @Override
        public void write(List<? extends T> items) {
            super.write(items);
            EntityManager entityManager = EntityManagerFactoryUtils.getTransactionalEntityManager(entityManagerFactory);

            if (entityManager == null) {
                throw new DataAccessResourceFailureException("Unable to obtain a transactional EntityManager");
            }

            entityManager.clear();
        }

        @Override
        public void setEntityManagerFactory(EntityManagerFactory entityManagerFactory) {
            super.setEntityManagerFactory(entityManagerFactory);
            this.entityManagerFactory = entityManagerFactory;
        }
    }

您可以看到添加的entityManager.clear();写方法中的

作业配置:

@Bean
public JpaItemWriter postgresWriter() {
    JpaItemWriter writer = new ClearingJpaItemWriter();
    writer.setEntityManagerFactory(pgEntityManagerFactory);
    return writer;
}

@Bean
    public Step appontmentInitStep(JpaItemWriter<Appointment> writer, FlatFileItemReader<Appointment> reader) {
        return stepBuilderFactory.get("initEclinicAppointments")
                .transactionManager(platformTransactionManager)
                .<Appointment, Appointment>chunk(5000)
                .reader(reader)
                .writer(writer)
                .faultTolerant()
                .skipLimit(1000)
                .skip(FlatFileParseException.class)
                .build();
    }

@Bean
    public Job appointmentInitJob(@Qualifier("initEclinicAppointments") Step step) {
        return jobBuilderFactory.get(JOB_NAME)
                .incrementer(new RunIdIncrementer())
                .preventRestart()
                .start(step)
                .build();
    }

共有1个答案

丰智
2023-03-14

这是一个有效的观点。JpaItemWriter(和HibernateItemWriter)用于清除持久上下文,但它已在BATCH-1635中删除(这是删除它的提交)。但是,这已通过clearSession参数(请参阅此提交)在BATCH-1759中的HibernateItemWriter中重新添加并可配置,但在JpaItemWriter中没有。

因此,我建议针对Spring Batch打开一个问题,以向JpaItemWriter添加相同的选项,以便在编写项目后清除持久性上下文(这将与HibernateItemWriter一致)。

也就是说,为了回答您的问题,您确实可以使用自定义编写器来清除持久性上下文。

希望这有所帮助。

 类似资料:
  • 问题内容: 我认为我的android应用正在泄漏内存。我不是绝对确定这是问题所在。 应用程序打开时经常崩溃,并且logcat尝试加载位图图像时会显示“内存不足”异常。 崩溃后,我重新打开了该应用程序,它运行正常。Logcat会显示许多“ gc”,并且JIT表会不时地向上调整大小,而不会向下调整,直到应用程序因内存不足错误而崩溃。 这听起来像是内存泄漏吗?如果是这样,我该如何定位和关闭泄漏点。 这是

  • 问题内容: 我一直在追寻内存泄漏(由“ valgrind –leak-check = yes”报告),它似乎来自ALSA。这段代码已经存在于自由世界中一段时间​​了,所以我猜这是我做错的事情。 输出看起来像这样: 并继续一些页面 这是由于我在一个项目中使用ALSA并开始看到这种巨大的泄漏……或者至少是所说泄漏的报告。 所以问题是:是我,ALSA或valgrind在这里遇到问题吗? 问题答案: ht

  • 问题内容: 我有一个长时间运行的脚本,如果让脚本运行足够长的时间,它将消耗系统上的所有内存。 在不详细介绍脚本的情况下,我有两个问题: 是否有可遵循的“最佳实践”,以防止泄漏发生? 有什么技术可以调试Python中的内存泄漏? 问题答案: 看看这篇文章:跟踪python内存泄漏 另外,请注意,垃圾收集模块实际上可以设置调试标志。看一下功能。此外,请查看Gnibbler的这段代码,以确定调用后已创建

  • 本文向大家介绍Java 内存泄漏,包括了Java 内存泄漏的使用技巧和注意事项,需要的朋友参考一下 在Java中,垃圾回收(析构函数的工作)是使用垃圾回收自动完成的。但是,如果代码中有引用它们的对象怎么办?它无法取消分配,即无法清除其内存。如果这种情况一再发生,并且创建或引用的对象根本没有被使用,它们就会变得无用。这就是所谓的内存泄漏。 如果超过了内存限制,则程序将通过抛出错误(即“ OutOfM

  • 问题内容: 我使用Informix遇到了一个奇怪的问题(具体来说,我使用的是IBM.Data.Informix命名空间,即4.10 Client SDK)。我正在使用ODBC连接到IBM Informix数据库,并且遇到内存泄漏问题。该文档相当稀疏,并且我只能使用当前安装的驱动程序/ SDK。这是我用于数据库上下文的代码: } 我已尝试处置并关闭所有可以的连接,但这似乎无济于事。我是否缺少某些东西

  • 我有一个后台服务正在运行,它正在将数据同步到我的服务器。 泄漏发生在以下代码中: 内存分析器显示: stockserv.datasyncer.jobexecutor@0x135f6550上的线程保留了总大小为18.603.056(37,90%)字节的局部变量。内存累积在“”加载的“java.lang.Object[]”的一个实例中。 JobExecutor->Arraylist->Object[2