双向变得比单向慢得多



在Java/Hibernate应用程序中,我有两个类CatKitten双向关系,如下所示:

public class Cat {
...
@OneToMany(mappedBy="cat", fetch = FetchType.LAZY)
@OnDelete(action = OnDeleteAction.CASCADE)
@LazyCollection(LazyCollectionOption.EXTRA)
@Getter
@Setter
private List<Kitten> kittens = new LinkedList();
public void addKitten(Kitten k) {
kittens.add(k);
}
...
}  
public class Kitten {
...   
@ManyToOne(fetch=FetchType.LAZY)
@Getter
@Setter
private Cat cat;
...
}

在一个巨大的 for 循环中,20000 个Kitten被添加到之前创建的不同Cat实体中。for 循环中的重要代码如下所示:

....
Kitten k = new Kitten();
k.setAttribut("foo");
k.setCat(currentCat);     // (a) line
currentCat.addKitten(k);  // (b) line
daoFactory.getKittenDao().save(k);
...

代码正在工作,但不知何故性能非常慢。在以前的迭代(单向(中,应用程序要快得多。由于最终版本应该适用于 1000000Kitten因此必须有改进的方法。如果我对上述代码的时间进行基准测试,大约需要 40 秒。如果我通过删除行 (a( 或 (b( 来模拟单向,则在这两种情况下都需要 10 秒(但如果我访问对象,则需要稍后

(。所以我的问题是: 我错过了什么,还是在Hibernate中双向关系的内部维护非常缓慢?由于模拟单向要快得多,因此我预计双向的运行时间约为 15 秒。

更新:

保存实体的代码位于 SAX 分析器默认处理程序实现中。因此,在解析 XML 结构时,首先将Cat保存在startElement()函数中,然后Kitten将保存在另一个startElement()调用中。 关于@Bartun的建议/问题:我研究了批处理。问题是,通过使用 DAO 和startElement()函数,很难判断何时保存了 50 个实体来刷新会话。不过,计数器可以解决问题。但是,它不能通过建立双向来解释性能影响。 作为事务管理,Spring@Transactional用于启动 XML 解析的函数。

我已经将处理时间缩短到我可以接受的值。它并没有真正解决我的问题,但大大减少了时间。如果其他人有同样的问题,这里是当前的代码和一个简短的解释。

public class Cat {
...
@OneToMany(mappedBy="cat", fetch = FetchType.LAZY)
@OnDelete(action = OnDeleteAction.CASCADE)
@LazyCollection(LazyCollectionOption.EXTRA)
@Getter
@Setter
private Set<Kitten> kittens = new HashSet();
public void addKitten(Kitten k) {
k.setCat(this);
if (Hibernate.isInitialized(kittens)) kittens.add(k); //line X
}
...
}  
public class Kitten {
...   
@ManyToOne(fetch=FetchType.LAZY)
@OnDelete(action = OnDeleteAction.CASCADE)
@Getter
@Setter
private Cat cat;
...
}
  • 最重要的是line X。在原始代码中,每次添加小猫时,都会从数据库中加载整个小猫列表。正如我在这里发现的那样,如果列表尚未初始化,则不得添加小猫。我知道,这必须小心完成,因为在首次初始化列表之前,必须将每只小猫保存在数据库中。否则一切都会不同步。
  • 上面的代码中没有说明,我更改了小猫持久性的结构以启用批量插入(链接的 Thx Bartun(。现在,所有小猫都在解析过程结束时使用批处理进行保存,而不是单独保存每只小猫。
  • 另一个小改进是从List更改为Set,以便在代码后面启用多个fetch joins

你在哪里开立交易? 确保您使用的是一笔交易

此外,您应该对此类数量使用批处理查询

有关批处理 https://vladmihalcea.com/how-to-batch-insert-and-update-statements-with-hibernate/的详细信息

您还可以使用休眠静态检查刷新计数和其他内容 https://www.thoughts-on-java.org/how-to-activate-hibernate-statistics-to-analyze-performance-issues/

当您处理如此数量的入口时,您需要完全控制刷新/批处理

相关内容

  • 没有找到相关文章

最新更新