Утечка памяти в Spring Batch - CSV в базу данных с использованием JpaItemWriter - PullRequest
0 голосов
/ 18 февраля 2019

У меня была проблема с заданием Spring Batch для чтения большого CSV-файла (несколько миллионов записей) и сохранения записей из него в базе данных.Задание использует FlatFileItemReader для чтения CSV и JpaItemWriter для записи прочитанных и обработанных записей в базу данных.Проблема в том, что JpaItemWriter не очищает контекст персистентности после сброса еще одного куска элементов в базу данных, и задание заканчивается на OutOfMemoryError.

. Я решил проблему, расширив JpaItemWriter ипереопределив метод write, чтобы он вызывал 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 Ответ

0 голосов
/ 19 февраля 2019

Это верный момент.JpaItemWriterHibernateItemWriter) используется для очистки постоянного контекста, но он был удален в BATCH-1635 (Здесь коммит , который его удалил).Однако это было повторно добавлено и стало настраиваемым в HibernateItemWriter in BATCH-1759 через параметр clearSession (См. Этот commit ), но не в JpaItemWriter.

Поэтому я предлагаю открыть проблему в Spring Batch для добавления этой же опции к JpaItemWriter, чтобы очистить контекст постоянства после записи элементов (это будет соответствовать HibernateItemWriter)..

Тем не менее, чтобы ответить на ваш вопрос, вы действительно можете использовать собственный писатель, чтобы очистить контекст постоянства, как вы это сделали.

Надеюсь, это поможет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...