Пакетная вставка сущностей в БД (Кваркус, спящий режим)

#java #hibernate #vert.x #quarkus

Вопрос:

Во-первых: Я не привык к Кварку или спящему режиму (я почти полностью в .net)

Проблема:

Мой сервис получает список из ~10 тысяч (думаю, это самый распространенный номер). Это происходит через конечную точку ресурса, и для его завершения требуется 10 секунд, очень долго. И служба не отвечает.

 *Endpoint -> Service/Business -> DAO*

@Override
public void create(FooBusiness foo) {

    var statuses = new ArrayList<StatusDto>();

    for(var i = 1; i < foo.getFromList().size(); i  ){

        var bar = foo.getFromList().get(i);
        statuses.add(new StatusDto(bar.x, bar.y));
    }
    statusDao.create(statuses);
}
 

В statusDao.Create() есть аннотации с @Transactional :

ДАО-это @ApplicationScoped

И эта ЭМ -:

 @PersistenceContext
EntityManager entityManager;
 

statusDao.Создать():

 @Transactional
public List<StatusDto> create(List<StatusDto> dto) {

    for(var i = 0; i < dto.size(); i  ){

        var status = dto.get(i);
        status.setCreatedTimestamp(LocalDateTime.now());
        entityManager.persist(status);
    }

    entityManager.flush();

    return dto;
}
 

Я читал много сообщений об этом, и многие из них предлагают это свойство, и разделите цикл сохранения, чтобы он соответствовал размеру пакета:
кваркус.спящий режим-orm.jdbc.оператор-размер пакета

Проблема в том, что когда я добавляю его в приложение.свойства, я получаю это изменение:

Не удается разрешить элемент конфигурации «размер пакета-инструкции»

Я потратил почти день, пытаясь найти решения о том, как ускорить процесс, что-нибудь очевидное, что я пропустил здесь?

И/или:

Могу ли я обернуть вызов от service к dao в какой-то магический огонь и забыть вызов, встроенный в Кваркус или Верт.х?

Комментарии:

1. Может быть, вы можете попробовать Hibernate Reactive: hibernate.org/reactive . Существует также краткое руководство по использованию его с Quarkus: github.com/quarkusio/quarkus-quickstarts/tree/main/…

2. Я изучил это очень быстро, но, насколько я понимаю, это еще не поддерживает базу данных H2? Я попробую это с помощью mariadb, но принято решение, что мы используем H2 в качестве стандарта и при необходимости переопределяем его на серверах. РЕДАКТИРОВАТЬ: При попытке сделать это я использовал MariaDB, а не H2.

Ответ №1:

Режим гибернации сохраняет все объекты, которые вы сохраняете, в контексте сохранения, поэтому вы будете приобретать все больше и больше памяти, что может привести к снижению производительности. Если вам больше не нужны эти объекты, как кажется, вы можете очистить и очистить их, например, партиями по 50 предметов.

 for (var i = 0; i < dto.size();) {
    var status = dto.get(i);
    status.setCreatedTimestamp(LocalDateTime.now());
    entityManager.persist(status);
    i  ;
    if ((i % 50) == 0) {
        entityManager.flush();
        entityManager.clear();
    }
}
entityManager.flush();
 

Комментарии:

1. Это действительно ускоряет процесс, поэтому я отмечу это как правильное. Но странно, что я не могу заставить собственность работать. Спасибо!

2. Свойство является дополнительной конфигурацией, позволяющей также выполнять пакетирование на уровне JDBC. Обычно лучше всего выровнять размеры пакетов, которые вы используете для достижения наилучшей производительности.

Ответ №2:

Трудно ответить на этот вопрос окончательно, если вы не определили точную причину плохого времени отклика. В принципе это может быть связано с:

  1. задержка, связанная со многими запросами к серверу базы данных,
  2. накладные расходы на закрепление многих объектов сущностей в памяти в сеансе с сохранением состояния гибернации или даже
  3. стоимость приема и анализа входящих данных.

Давайте предположим, что это не 3.

  • Если это 2, то, действительно, пакетирование JDBC поможет, и вам просто нужно выяснить, как заставить это свойство конфигурации работать.
  • Но я предполагаю, что Кристиан прав, и проблема заключается в накоплении данных в контексте сохранения. Если это предположение верно , то есть два возможных решения: одно-использовать a StatelessSession , которое было разработано с учетом такого рода использования, а другое-использовать flush() и clear() , как описано Кристианом.

Я бы рекомендовал использовать StatelessSession , если только проблема на самом деле не заключается в комбинации 2 3, и в этом случае вам нужны как пакетирование, так и управление контекстом сохранения, а затем в этом случае делайте то, что предлагает Кристиан.

Комментарии:

1. Спасибо! Да, я знаю, что трудно точно указать на проблему, когда нет всех фактов и данных.