Как пружинные данные очищают сохраненные сущности в транзакционном методе? - PullRequest
0 голосов
/ 11 января 2019

Мне нужно получать и сохранять огромное количество данных, используя весенние данные в спящем режиме. Наш сервер выделил недостаточно ОЗУ для сохранения всех сущностей одновременно. Мы обязательно получим ошибку OutOfMemory.

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

Итак, вопрос: сохраняют ли данные пружины в методе @Transactional сущности в ОЗУ или очищенные сущности доступны сборщику мусора?

Итак, каков наилучший подход для обработки огромного количества данных с данными Spring? Может быть, весенние данные не правильный подход к решению подобных проблем.

1 Ответ

0 голосов
/ 11 января 2019

Сохраняет ли данные пружины во время метода @Transactional объекты в ОЗУ или объекты, которые были очищены, доступны для мусора коллектор

Объекты будут храниться в ОЗУ (т. Е. В entityManager) до тех пор, пока не будет очищен фиксация / откат транзакции или entityManager. Это означает, что сущности имеют право на GC только в случае фиксации / отката транзакции или entityManager.clear() называется.

Итак, каков наилучший подход для обработки огромного количества данных с данные весны?

Общая стратегия предотвращения OOM заключается в загрузке и обработке пакета данных за пакетом. В конце каждого пакета вы должны очищать и очищать entityManager, чтобы entityManager мог высвобождать свои управляемые объекты для CG. Общий поток кода должен выглядеть примерно так:

@Component
public class BatchProcessor {

    //Spring will ensure this entityManager is the same as the one that start transaction due to  @Transactional
    @PersistenceContext
    private EntityManager em;

    @Autowired
    private FooRepository fooRepository;

    @Transactional
    public void startProcess(){

        processBatch(1,100);
        processBatch(101,200);
        processBatch(201,300);
        //blablabla

    }

    private void processBatch(int fromFooId , int toFooId){
        List<Foo> foos =  fooRepository.findFooIdBetween(fromFooId, toFooId);
        for(Foo foo :foos){
            //process a foo
        }

        /*****************************
        The reason to flush is send the update SQL to DB . 
        Otherwise ,the update will lost if we clear the entity manager 
        afterward.
        ******************************/
        em.flush();
        em.clear();
    }
} 

Обратите внимание, что эта практика предназначена только для предотвращения ООМ, но не для достижения высокой производительности. Поэтому, если производительность не является вашей заботой, вы можете смело использовать эту стратегию.

...