fyl*_*eow 5 optimization hibernate
我正在尝试使用Hibernate来提高应用程序的性能,Hibernate正在对数据库执行过多的SQL调用.我认为数据获取可以组合在一起以减少调用并提高性能,但我在这里有点不知所措.我看过关于子选择和批量提取的Hibernate文档,这确实有帮助,但我不认为它完全消除了这个问题.
在下面的示例中,我需要获取属于部队的士兵列表的详细信息并将其显示在网页上.
@Entity
public class Troop {
@OneToMany(mappedBy="troop")
public List<Soldier> getSoldiers() {
...
}
Run Code Online (Sandbox Code Playgroud)
很容易将获取策略设置为subselect,batch或eager,以便在没有太多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() {
...
}
Run Code Online (Sandbox Code Playgroud)
每个士兵实体与其他懒惰加载的实体有多个一对多的关系.我需要初始化这些集合并从中检索值.如果士兵有3对一对多的关系,而且一支部队有1000名士兵,那将导致3 x 1,000个SQL呼叫!
有没有办法通过减少通话次数来优化这一点?既然我已经知道我需要检索的士兵,我可以检索实体并让它们在第一级缓存中可用吗?
例如,我可以查询
from Address as a where a.soldierId in (...)
from CombatHistory as a where a.soldierId in (...)
from MedicalHistory as a where a.soldierId in (...)
Run Code Online (Sandbox Code Playgroud)
如果可以缓存Address,CombatHistory等实体,那么在每个士兵中访问集合时将不会执行SQL选择.这将减少每个集合一个呼叫的数量(在这种情况下为3个),而不是每个战士每个集合一个(3 x 1000)
我在文档中没有真正看到关于解决这个问题的内容,因此非常感谢任何提示和想法.请记住,由于这些集合是列表而不是集合,因此无法在多个集合上执行左连接提取,或者Hibernate将返回异常.
HibernateException: cannot simultaneously fetch multiple bags
Run Code Online (Sandbox Code Playgroud)
如果您“触摸”该类型的一个集合,您还可以在集合上使用注释 @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;
}
...
}
Run Code Online (Sandbox Code Playgroud)
以下是如何使用它的示例:
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;
}
Run Code Online (Sandbox Code Playgroud)
日志:
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
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
6667 次 |
| 最近记录: |