Длительная работа persist заканчивается ошибками

Это мой код, пытающийся сохранить данные

`     for (int i = 0; i < materialVersions.size(); i += BATCH_SIZE) {
            int endIndex = Math.min(i + BATCH_SIZE, materialVersions.size());
            List<MaterialVersion> materialVersionChunk = materialVersions.subList(i, endIndex);

            for (MaterialVersion materialVersion : materialVersionChunk) {
                materialVersion.setReferencedEntities(referencedEntities);
                materialVersionRepo.persist(materialVersion);
            }`

это в контексте транзакции

referencedEntities имеет onetomany с MaterialVersion, и соединение является двунаправленным. это сохранение происходит частями, это Java-приложение Quarkus.

это мои объекты недвижимости

quarkus.hibernate-orm.jdbc.fetch.batch-size=100

quarkus.transaction-manager.default-transaction-timeout=3600

но поскольку MaterialVersion много, это большой список, в результате которого я получаю исключение нравиться

{"timestamp":"04:21:27.909","sequence":20079,"loggerClassName":"org.jboss.logging.Logger","loggerName":"io.agroal.pool","level":"WARN","message":"Datasource '<default>': ORA-17008: Closed connection\nhttps://docs.oracle.com/error-help/db/ora-17008/","threadName":"Transaction Reaper Worker 0","threadId":58,"mdc":{},"ndc":"","hostName":"85b64c4fc1dd","processName":"quarkus-run.jar","processId":1} {"timestamp":"04:21:28.019","sequence":20080,"loggerClassName":"org.hibernate.internal.CoreMessageLogger_$logger","loggerName":"org.hibernate.resource.transaction.backend.jta.internal.synchronization.SynchronizationCallbackCoordinatorTrackingImpl","level":"WARN","message":"HHH000451: Transaction afterCompletion called by a background thread; delaying afterCompletion processing until the original thread can handle it. [status=4]","threadName":"Transaction Reaper Worker 0","threadId":58,"mdc":{},"ndc":"","hostName":"85b64c4fc1dd","processName":"quarkus-run.jar","processId":1}

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

Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
0
0
52
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вместо открытия одной длинной транзакции вы также можете выполнять пакетные транзакции.

Что-то вроде этого:

@ConfigProperty(name = "quarkus.hibernate-orm.jdbc.statement-batch-size", defaultValue = "20")
    int batchSize;

    @Inject
    Entitymanager em;

    public void store(@NotEmpty @NotNull List<MaterialVersion> versions) {
            var index=0;
            try {
                for (var i = 0; i < versions.size(); i++) {    
                   em.getTransaction().begin();                
                   var endIndex = Math.min(i + batchSize, versions.size());
                   var materialVersionChunk = versions.subList(i, endIndex);

                   for (var j = 0; j < materialVersionChunk.size(); j++) {
                       if (j > 0 && this.batchSize % j == 0) {
                          em.getTransaction().commit();
                          em.clear();
                          em.getTransaction().begin();
                       }
                       materialVersionChunk.get(j).setReferencedEntities(referencedEntities);
                       materialVersionRepo.persist(materialVersion);
                   }
                   index++;
                   em.getTransaction().commit();
               }
               
            } catch (Exception ex) {
               em.getTransaction().rollback();
               throw new WebApplicationException("Failed persisting at index %d".formatted(index), 400);
            }
  }
    

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