gpt4 book ai didi

hibernate - JPA 坚持变得越来越慢

转载 作者:行者123 更新时间:2023-12-01 15:58:35 25 4
gpt4 key购买 nike

这个场景使用一个简单的 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();
}

该测试是一个无限循环,它尝试插入 20000 个与单个 One 实体关联的 Many 实体。每个循环都从创建一个新的 EntityManagerFactory 开始,以显示不断增加的数据库对性能的负面影响。

预期的行为是,实体的插入时间不会急剧增加,但是在每个 WHILE CYCLE 之后都会有一个数量级的增加。

注意事项:

  • 我已经尝试过 eclipseLink、Hibernate、OpenJPA 并且都遇到了这种减速问题。
  • 如果我不更新 One 的 Many 集合,则不会出现降级(请参阅 Many 的注释行)。
  • 如果我不创建新的 EntityManagerFactory,那么即使在 50 万个实体之后也不会降级。
  • 慢的部分是em.persist(many);(我测过的)。
  • 查看 https://github.com/kupsef/OneToMany并开始测试gradle 开始

为什么在这种情况下数据库的初始大小很重要?我应该将此行为视为错误吗?

最佳答案

只是为了扩展 Predrag 的回答——遍历 1:M 关系不仅有引入实体的成本,而且任何扩展对象图,但这些实体仍然在持久单元内管理。因为您的测试为重复事务重复使用相同的 EntityManager,所以托管实体的缓存会随着每次迭代而持续增长。每次上下文与数据库同步时,都必须遍历并检查托管实体的缓存是否有更改 - 这发生在刷新、事务提交甚至查询时。

如果您必须引入大型对象图,可以采取的措施是为每个事务边界释放和获取新的 EntityManager,或者偶尔刷新并清除 EntityManager。任一选项都允许它释放一些托管实体,因此它不需要在每次提交时检查所有实体是否有更改。

编辑>您的“Many”类已覆盖 hashCode 方法,并使用其引用的“One”的哈希码及其主键来构建其哈希码。这会导致您在循环中坚持的每个“许多”都具有相同的哈希码,因为 GenerationType.IDENTITY 只能在插入语句发生时分配序列 - 这发生在同步(刷新/提交)期间。此方法可能会导致缓存查找(由于级联持久调用而导致提供程序在每个持久调用上遍历不断增长的对象模型时发生)花费越来越长的时间。

关于hibernate - JPA 坚持变得越来越慢,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35700404/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com