Это мой код, пытающийся сохранить данные
` 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, это в некоторой степени помогает, но решение не является последовательным, поскольку для некоторых других значений контроллера список может стать еще больше.
Вместо открытия одной длинной транзакции вы также можете выполнять пакетные транзакции.
Что-то вроде этого:
@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);
}
}