gpt4 book ai didi

hibernate - 如何优化在 Hibernate 中获取多个集合?

转载 作者:行者123 更新时间:2023-12-02 20:10:26 24 4
gpt4 key购买 nike

我正在尝试提高使用 Hibernate 的应用程序的性能,该应用程序对数据库执行了太多 SQL 调用。我认为数据获取可以组合在一起以减少调用并提高性能,但我在这里有点不知所措。我查看了有关子选择和批量获取的 Hibernate 文档,这确实有帮助,但我认为它并不能完全消除问题。

在下面的示例中,我需要获取属于部队的士兵列表的详细信息并将其显示在网页上。

@Entity
public class Troop {
@OneToMany(mappedBy="troop")
public List<Soldier> getSoldiers() {
...
}

很容易将获取策略设置为子选择、批量或急切检索该部队的所有士兵部分,而无需太多 SQL 语句。

@Entity
public class Soldier {
@Id
String soldierId

String firstName;
String lastName;

@OneToMany(mappedBy="address")
public List<Soldier> getAddress() {
...
@OneToMany(mappedBy="combatHistory")
public List<Soldier> getCombatHistory() {
...
@OneToMany(mappedBy="medicalHistory")
public List<Soldier> getMedicalHistory() {
...
}

每个士兵实体与延迟加载的其他实体都有多个一对多的关系。我需要初始化这些集合并从中检索值。如果一个士兵有 3 个一对多关系,一个部队有 1,000 名士兵,这将导致 3 x 1,000 个 SQL 调用!

有没有办法通过减少调用次数来优化这一点?由于我已经知道需要检索的士兵 ID,我可以检索实体并将它们放在一级缓存中吗?

例如我可以查询

from Address as a where a.soldierId in (...)
from CombatHistory as a where a.soldierId in (...)
from MedicalHistory as a where a.soldierId in (...)

如果可以缓存地址、CombatHistory 等实体,那么在每个士兵中访问该集合时将不会执行 SQL 选择。这会将调用次数减少到每个集合一次(本例中为 3 个),而不是每个士兵每次集合一次 (3 x 1000)

我在文档中并没有真正看到太多有关解决此问题的内容,因此非常感谢任何提示和想法。请记住,由于这些集合是列表而不是集合,因此无法在多个集合上执行左连接获取,否则 Hibernate 将返回异常。

HibernateException: cannot simultaneously fetch multiple bags 

最佳答案

您还可以在集合上使用注释 @Fetch(FetchMode.SUBSELECT)如果您“接触”该类型的一个集合,则所有集合都将在一个 SQL 请求中获取。

@Entity
public class Country implements java.io.Serializable {

private long id;
private int version;
private String country;
private Set<City> cities = new HashSet<City>(0);

@Fetch(FetchMode.SUBSELECT)
@OneToMany(mappedBy = "country", cascade = CascadeType.ALL)
public Set<City> getCities() {
return cities;
}


...
}

以下是如何使用它的示例:

    public List<Country> selectCountrySubSelect() {
List<Country> list = getSession().createQuery("select c from Country c").list();
// You don't have to initialize every collections
// for (Country country : list) {
// Hibernate.initialize(country.getCities());
// }
// but just "touch" one, and all will be initialized
Hibernate.initialize(((Country) list.get(0)).getCities());
return list;
}

日志:

DEBUG org.hibernate.engine.loading.internal.CollectionLoadContext.endLoadingCollections():  - 2 collections were found in result set for role: business.hb.Country.cities
DEBUG org.hibernate.engine.loading.internal.CollectionLoadContext.endLoadingCollection(): - Collection fully initialized: [business.hb.Country.cities#1]
DEBUG org.hibernate.engine.loading.internal.CollectionLoadContext.endLoadingCollection(): - Collection fully initialized: [business.hb.Country.cities#2]
DEBUG org.hibernate.engine.loading.internal.CollectionLoadContext.endLoadingCollections(): - 2 collections initialized for role: business.hb.Country.cities
DEBUG org.hibernate.engine.internal.StatefulPersistenceContext.initializeNonLazyCollections(): - Initializing non-lazy collections

关于hibernate - 如何优化在 Hibernate 中获取多个集合?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11605967/

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