Hibernate3中取得多层数据的所产生的n+1 selects问题的解决。 其实这个问题在Hibernate in Action中已经有很多种解决办法了。但我觉得其中最好的办法是用Criteria的FetchMode来解决,但是Hibernate in Action中写的很不详细。我昨晚试了好长时间来的到答案。下面总结一下。
需求这样的,我有四张表(one,two,three,four)从one一直外键关联到four。结构如下
现在在Session中得到One,并从One里一直取到Four里的内容。如果简单的用Session.get来实现是这样的。
One one = (One)session.get(One.class,new Integer(1));
Iterator iterone = one.getTwos().iterator();
while(iterone.hasNext()){
Two two = (Two) iterone.next();
Iterator itertwo = two.getThrees().iterator();
while(itertwo.hasNext()){
Three three = (Three) itertwo.next();
three.getFours().size();
}
}这样我在Session关闭后返回的One里是从One到Four的信息都有的。
然而这样做所导致的结果是生成大量的SQL查询,这是一个典型的n+1 Selects问题。如果系统结构层次多,符合条件的记录多,那么Hibernate为你生成的SQL查询将是难以接受的。
对于这个例子生成的SQL是这样的
Hibernate: select one0_.c_one_id as c1_0_, one0_.c_one_text as c2_3_0_ from One one0_ where one0_.c_one_id=?
Hibernate: select twos0_.c_one_id as c2_1_, twos0_.c_two_id as c1_1_, twos0_.c_two_id as c1_0_, twos0_.c_one_id as c2_2_0_, twos0_.c_two_text as c3_2_0_ from Two twos0_ where twos0_.c_one_id=?
Hibernate: select threes0_.c_two_id as c2_1_, threes0_.c_three_id as c1_1_, threes0_.c_three_id as c1_0_, threes0_.c_two_id as c2_1_0_, threes0_.c_three_text as c3_1_0_ from Three threes0_ where threes0_.c_two_id=?
Hibernate: select fours0_.c_three_id as c2_1_, fours0_.c_four_id as c1_1_, fours0_.c_four_id as c1_0_, fours0_.c_three_id as c2_0_0_, fours0_.c_four_text as c3_0_0_ from Four fours0_ where fours0_.c_three_id=?
Hibernate: select fours0_.c_three_id as c2_1_, fours0_.c_four_id as c1_1_, fours0_.c_four_id as c1_0_, fours0_.c_three_id as c2_0_0_, fours0_.c_four_text as c3_0_0_ from Four fours0_ where fours0_.c_three_id=?
Hibernate: select threes0_.c_two_id as c2_1_, threes0_.c_three_id as c1_1_, threes0_.c_three_id as c1_0_, threes0_.c_two_id as c2_1_0_, threes0_.c_three_text as c3_1_0_ from Three threes0_ where threes0_.c_two_id=?
Hibernate: select fours0_.c_three_id as c2_1_, fours0_.c_four_id as c1_1_, fours0_.c_four_id as c1_0_, fours0_.c_three_id as c2_0_0_, fours0_.c_four_text as c3_0_0_ from Four fours0_ where fours0_.c_three_id=?
Hibernate: select fours0_.c_three_id as c2_1_, fours0_.c_four_id as c1_1_, fours0_.c_four_id as c1_0_, fours0_.c_three_id as c2_0_0_, fours0_.c_four_text as c3_0_0_ from Four fours0_ where fours0_.c_three_id=?
对于这样的问题,在没有Hibernate以前我们一般都用jdbc来做,那样的话我们其实用一个进行3次join的sql语句就可以实现,但是这样解决也有问题,就是返回的ResultSet中的数据非常多,而且杂乱,其实是从one到four平行排列的。对于这样的结果集我们要把它手动影射曾对象结构也是一个很复杂的操作。
幸好Hibernate3可以为我们做这些事情(我再一次被Hibernate的强大所震撼)。
上面的实现可以用Criteria来实现:
session = sessionFactory.openSession();
Criteria criteria = session.createCriteria(One.class);
criteria.add(Expression.eq("COneId",new Integer(1)));
one = (One)criteria.setFetchMode("twos",FetchMode.JOIN).setFetchMode("twos.threes",FetchMode.JOIN).setFetchMode("twos.threes.fours",FetchMode.JOIN).uniqueResult();
session.close();
这里的重点是这句话criteria.setFetchMode("twos",FetchMode.JOIN).setFetchMode("twos.threes",FetchMode.JOIN).setFetchMode("twos.threes.fours",FetchMode.JOIN).uniqueResult();
在用Criteria之前先设置FetchMode,应为Criteria是动态生成sql语句的,所以生成的sql就是一层层Join下去的。
setFetchMode(String,Mode)第一个参数是association path,用"."来表示路径。这一点具体的例子很少,文档也没有写清楚。我也是试了很久才试出来的。
就这个例子来所把因为取道第四层,所以要进行三次setFetchMode
第一次的路径是twos,一位one中有two的Set。这个具体要更具hbm.xml的配置来定。
第二个路径就是twos.threes
第三个就是twos.threes.fours
一次类推,一层层增加的。
这样做法最终生成的SQL是这样的:
Hibernate: select this_.c_one_id as c1_3_, this_.c_one_text as c2_3_3_, twos2_.c_one_id as c2_5_, twos2_.c_two_id as c1_5_, twos2_.c_two_id as c1_0_, twos2_.c_one_id as c2_2_0_, twos2_.c_two_text as c3_2_0_, threes3_.c_two_id as c2_6_, threes3_.c_three_id as c1_6_, threes3_.c_three_id as c1_1_, threes3_.c_two_id as c2_1_1_, threes3_.c_three_text as c3_1_1_, fours4_.c_three_id as c2_7_, fours4_.c_four_id as c1_7_, fours4_.c_four_id as c1_2_, fours4_.c_three_id as c2_0_2_, fours4_.c_four_text as c3_0_2_ from One this_ left outer join Two twos2_ on this_.c_one_id=twos2_.c_one_id left outer join Three threes3_ on twos2_.c_two_id=threes3_.c_two_id left outer join Four fours4_ on threes3_.c_three_id=fours4_.c_three_id where this_.c_one_id=?
虽然很长但是只有一条SQL语句。性能要好很多。Hibernate的强大之处是它会把返回的ResultSet自动影射到你的对象模型里面去。这就为我们省了很多事。
看来Hibernate真是一个耐人寻味的Framework啊。
分享到:
相关推荐
selects[i].onclick = new Function("clickLabels3('"+selects[i].name+"');window.event.cancelBubble = true;"); } else if(!isIE){ selects[i].onclick = new Function("clickLabels3('"+selects[i]....
Excel 数据处理技巧 Excel 是一个功能强大的电子表格软件,广泛应用于数据处理和分析领域。今天,我们将讨论如何使用 Excel 对大量数据进行求和和排序。 使用 Excel 对大量数据进行求和 在数据处理中,求和是最...
1. **实时搜索**:用户在输入框中输入时,后台根据输入的内容即时返回匹配的数据,显示在下拉框中。 2. **自定义后端接口**:允许开发者定义自己的后端视图函数或类来处理Ajax请求,灵活地控制数据的过滤和返回。 3....
- **Avoiding N+1 Selects (1:1)**:避免N+1次查询问题,提高性能。 - **Complex Collection Properties**:处理集合类型的属性。 - **Avoiding N+1 Selects (1:M and M:N)**:处理一对多或多对多关系时的查询...
django-smart-selects, 用于 Django 窗体的链接和分组选择 Django 智能选择 软件包允许你通过在模型中添加自定义外键或者许多字段来快速筛选或者组合"链接"模型。 这将使用一个AJAX查询来只加载适用的链接对象。警告...
+ 1.2.1 本手册中使用的约定 o 1.3 MySQL的历史 o 1.4 MySQL的主要特征 o 1.5 MySQL稳定性? o 1.6 顺应2000年 o 1.7 SQL一般信息和教程 o 1.8 有用的MySQL相关链接 * 2 MySQL 邮件列表及如何提问或报告错误...
### 数据结构公交车最优线路问题知识点解析 #### 一、项目背景及目标 本课程设计项目的目的是解决公交车线路上的优化路径查询问题。通过构建一个合理的数据模型,并应用算法找到两个站点间按照不同标准(如时间、...
通过遗传算法来筛选语音情感识别模型中特征_GA-selects-features-in-SER
RESET_N, ADDR, CMD, CMDACK, DATAIN, DATAOUT, // DM, SA, BA, CS_N, CKE, RAS_N, CAS_N, WE_N, DQ // DQM ); `include "params.v" input CLK; //System Clock input RESET_N; //System Reset ...
active/passive Distributed Replicated Block Device (DRBD):** DRBD通过在网络中的两个或多个服务器之间实时同步数据来实现数据复制。这种方式可以确保在主服务器发生故障时,被动服务器能够立即接管服务,从而...
This is a bit like the way Hibernate uses optimistic locking for versioned objects. The benefit is that lock contention is totally removed because there aren’t any locks on rows! This means that ...
在上面的代码中,DBManager类封装了JDBC连接数据库的步骤,使用getConnection()方法获取连接对象。 三、DBManager类详解 DBManager类是JDBC连接数据库的核心类,提供了getConnection()和executeUpdate()方法。 1....
在IT界,尤其是在Web开发和用户界面设计中,当面临大量数据需要展示在下拉列表(dropdown)中时,确实会遇到性能问题和用户体验的挑战。"当下拉列表数据过大时,该如何应对?"这个问题触及到了数据管理和UI优化的...
1. main.BAK、get_selects.BAK:这些是备份文件,通常包含程序中的重要数据或代码。"main"可能是主程序的备份,而"get_selects"可能涉及数据获取或查询的逻辑。 2. Reg.bat:这是一个批处理文件,可能用于注册或...
Avoiding N+1 Selects 为了避免常见的N+1查询问题,iBATIS提供了一些策略来优化多对多关系的查询效率。 #### 九、Caching Mapped Statement Results 为了提高性能,iBATIS支持对Mapped Statement的结果进行缓存...
在本实验中,我们将使用关系数据库selects来从数据库中检索数据,以便在消息流中使用关系数据库selects、IF-ELSE逻辑、ESQL过程、XPATH连接方法创建映射。 * IF-ELSE逻辑 IF-ELSE逻辑是一种用于控制消息流中数据处理...
Exact Audio Copy更新日志:1.0beta1 + Unicode support for all fields (but not CD -Text) + New database engine for storing CD information (old databases can be imported) + Metadata plugin support, ...
在IT行业中,前端开发是构建Web应用程序用户界面的关键部分,涉及到与用户交互的网页和应用的设计和实现。本文将深入探讨如何使用JSON数据在前端实现国民经济行业三级分类的四级联动功能。 首先,让我们理解什么是...
实验五 SQL 的视图 实验五 SQL 的视图实验...视图可以应用于各种数据库应用中,如数据报表、数据分析、数据挖掘等。视图可以帮助用户快速地获取所需的数据,并且可以隐藏基本表的复杂性,提高数据的安全性和可维护性。