【发布时间】:2016-06-12 13:01:08
【问题描述】:
此方案使用简单的 oneToMany 关系,并在两个方向上保持级联。
很多:
@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();
}
测试是一个无限循环,它尝试插入与单个 One 实体关联的 20000 个 Many 实体。每个循环都从创建一个新的EntityManagerFactory 开始,以显示不断增加的数据库对性能的负面影响。
预期的行为是,实体的插入时间不会急剧增加,但是在每个 WHILE CYCLE 之后会有一个数量级的增加。
注意事项:
- 我尝试过 eclipseLink、Hibernate、OpenJPA 并且都遇到过这种减速。
- 如果我不更新 One 的 Many 集合,则不会出现降级(请参阅 Many 的注释行)。
- 如果我不创建新的 EntityManagerFactory,那么即使在 50 万个实体之后也不会降级。
- 慢的部分是
em.persist(many);(我测了一下)。 - 查看https://github.com/kupsef/OneToMany 并使用以下命令开始测试
gradle start。
为什么在这种情况下数据库的初始大小很重要?我应该将此行为视为错误吗?
【问题讨论】:
-
为什么不看看日志就明白了?
-
您会建议哪些日志? sql 日志仅在第一个周期(内部 for)中有所不同,它还包含许多实体的获取。这并不能解释降级,因为随后的循环没有获取它们(很可能是因为它们被缓存以供以后使用,正如预期的那样)。
-
您使用的 JPA 实现的日志。我使用的实现(DataNucleus)总是显示大量信息来追踪潜在问题,所以我认为其他实现同样有用
-
persist 操作发出的唯一日志条目只是调用persist 的注释。没什么用。
标签: hibernate jpa eclipselink one-to-many persist