Этот сценарий использует простые отношения oneToMany с каскадом в обоих направлениях.JPA сохраняется медленнее и медленнее
Много:
@javax.persistence.Entity(name="Many")
public class Many {
@javax.persistence.ManyToOne(cascade = CascadeType.PERSIST)
protected One one;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long primaryKey;
public void setM(One one) {
this.one = one;
// comment out this line and performance becomes stable
this.one.getMany().add(this);
}
// other setters, getters, etc...
}
Один:
@javax.persistence.Entity(name="One")
public class One {
@javax.persistence.OneToMany(mappedBy="m", cascade = CascadeType.PERSIST)
protected java.util.Set<Many> many = com.google.common.collect.Sets.newHashSet();
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long primaryKey;
private String name;
// setters, getters, etc...
}
Тест:
public static void main(String[] args) {
while(true) {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("test-pu");
EntityManager em = emf.createEntityManager();
for (int i = 0; i < 100; i++) {
sw.reset();
sw.start();
persistMVs(emf, em);
System.err.println("Elapsed: " + sw.elapsed(TimeUnit.MILLISECONDS) + " ms");
}
em.close();
emf.close();
}
}
private static void persistMVs(EntityManagerFactory emf, EntityManager em) {
em.getTransaction().begin();
One one = getOrCreateOne(em);
for (int i = 0; i < 200; i++) {
Many many = new Many();
many.setM(one);
em.persist(many);
}
em.getTransaction().commit();
}
Испытание представляет собой бесконечную петлю, которая пытается вставить 20000 Many
объектов, связанных с одним объектом One
. Каждый цикл начинается с создания нового EntityManagerFactory
, чтобы показать отрицательный эффект производительности увеличивающейся базы данных.
Ожидаемое поведение будет заключаться в том, что время вставки объектов не резко возрастает, однако после каждого ВО ВРЕМЯ ЦИКЛА наблюдается увеличение величины порядка.
Примечания:
- Я попытался EclipseLink, Hibernate, OpenJPA и все страдали от такого спада.
- Если я не обновляю многие коллекции One, тогда нет деградации (см. Прокомментированную строку Many).
- Если я не создаю новый EntityManagerFactory, тогда нет деградации даже после полумиллиона объектов.
- Медленная часть
em.persist(many);
(я ее измерил). - Отъезд https://github.com/kupsef/OneToMany и начать тест с
gradle start
.
Зачем нужен начальный размер базы данных в этом случае? Должен ли я рассматривать это поведение как ошибку?
Почему вы не смотрите на журнал и не понимаете его? –
Какие журналы вы бы предложили? Журналы sql отличаются только в первом цикле (внутреннего для), он дополнительно содержит выборку из многих объектов. Это не объясняет деградацию, поскольку последующие циклы не извлекают их (скорее всего, потому, что они были кэшированы для последующего использования, как и ожидалось). – kupsef
журналы используемой вами функции JPA. Реализация, которую я использую (DataNucleus), всегда показывает много информации для отслеживания потенциальных проблем, поэтому я предполагаю, что другие одинаково полезны. –