攻城狮在路上(壹) Hibernate(十四)--- Hibernate的检索方式(下)
本节介绍HQL和QBC的高级用法:各种连接查询、投影查询、报表查询、动态查询、集合过滤和子查询等。另外将归纳优化查询程序代码,从而提高查询性能的各种技巧。
一、连接查询:
HQL与QBC支持的各种连接类型:
| 在程序中指定的连接查询类型 | HQL语法 | QBC语法 | 适用范围 |
| 内连接 | inner join 或者join |
Criteria.createAlias() | 适用于有关联关系的持久化类,并且在映射文件中对这种关联关系做了映射 |
| 迫切内连接 | inner join fetch 或者join fetch |
不支持 | |
| 隐式内连接 | 支持 | 不支持 | |
| 左外连接 | left outer join 或者left join | 不支持 | |
| 迫切左外连接 | left outer join fetch 或者left join fetch | FetchMode.JOIN | |
| 右外连接 | right outer join 或者 right join | 不支持 | |
| 交叉连接 | Class A, Class B | 不支持 | 适用于不存在关联关系的持久化类 |
1、默认情况下关联级别的运行时检索策略:
可以在映射文件中设置关联级别的立即检索、延迟检索或迫切左外连接检索。注意Query API会忽略迫切左外连接的配置。
若程序代码中没有显式指定与Customer类关联的Order对象的检索策略,那么将采用Customer.hbm.xml映射文件对orders集合设置的检索策略。
有个例外:HQL会忽略映射文件设置的迫切左外连接检索策略,详见下表。
HQL和QBC运行时对Customer类的orders集合使用的检索策略:
| Customer.hbm.xml文件对orders集合设置的检索策略 | HQL | QBC |
| 立即检索 | 立即检索 | 立即检索 |
| 延迟检索 | 延迟检索 | 延迟检索 |
| 迫切左外连接检索 | 立即检索 | 迫切左外连接检索 |
2、迫切左外连接:
若程序中显式指定了与Customer关联的Order对象的检索策略,则会覆盖Customer.hbm.xml中的设置。
实例代码:
//HQL检索方式
List result = session.createQuery("from Customer c left join fetch c.orders o where c.name like 'T%'").list();
//QBC检索方式:
list result = session.createCriteria(Customer.class)
.setFetchMode("orders", FetchMode.JOIN)
.add(Restrictions.like("name", "T", MatchMode.START)).list(); for(Iterator it = result.iterator(); it.hasNest()) {
Customer customer = (Customer)it.next();
}
HQL中,left join fetch关键字表示迫切左外连接检索策略。在QBC中,FetchMode.JOIN表示迫切左外连接检索策略。
使用Query或则Criteria的list()方法返回的集合中存放Customer对象的引用,每个Customer对象的orders集合都被初始化,存放所有管理的Order对象。
注意:当使用迫切左外连接检索策略时,查询结果中可能会包含重复元素,可以通过一个HashSet来过滤重复元素。
3、左外连接:
实例代码:
//HQL检索方式
//如果希望list()返回的集合中仅包含Customer对象,在HQL语句中使用select关键字即可。
List result = session.createQuery("from Customer c left join c.orders o where c.name like 'T%'").list();
for(Iterator paris = result.iteraor(); pairs.hasNext() {
Object[] pair = (Object[])pairs.next();
Customer customer = (Customer)pair[0];
Order order = (Order)pair[1];
//如果orders集合使用延迟加载策略,以下代码会初始化Customer对象的orders集合
customer.getOrders().iterator();
}
4、内连接:
在HQL中,使用inner join关键字表示内连接。另外QBC也支持内连接(createAlias("orders", "o"))。
实例代码:
List result = session.createQuery("from Customer c inner join c.orders o where c.name like 'T%'").list();
for(Iterator paris = result.iteraor(); pairs.hasNext() {
Object[] pair = (Object[])pairs.next();
Customer customer = (Customer)pair[0];
Order order = (Order)pair[1];
//如果orders集合使用延迟加载策略,以下代码会初始化Customer对象的orders集合
customer.getOrders().iterator();
}
QBC方式默认仅检索出Customer对象,若要希望QBC返回的集合也包含成对的Customer和Order对象,可以调用Critiria的setResultTransformer()方法。
5、迫切内连接:
通过inner join fetch关键字来指定,此种方式会覆盖映射文件中指定的检索策略。
QBC不支持迫切内连接。
6、隐式内连接:
HQL支持隐式内连接,QBC不支持。
7、右外连接:
在HQL中,使用right join关键字表示右外连接。
8、使用SQL风格的交叉连接盒隐式内连接:
此种情况多用于不存在关联关系的两个类:
from Customer, Student
9、关联级别运行时的检索策略:
该节时对关联级别运行时的检索策略的总结:
A、如何在HQL或QBC程序代码中没有显示的指定检索策略,将使用映射文件配置的检索策略,例外情况是:HQL总是忽略配置文件中设置的迫切左外连接检索策略。
B、如果在HQL或QBC程序代码中显示指定了检索策略,就会覆盖映射文件配置的检索策略。
C、HQL支持各种连接查询:left join fetch\left join\inner join fetch\inner join\right join
HQL在各种连接方式下的运行时行为:
| 连接方式 | 对应的SQL查询语句 | orders集合的检索策略 | 查询结果集中的内容 |
| 无连接 | 查询单个CUSTOMERS表 | 延迟检索策略 | 集合中包含Customer类型的元素; 集合中无重复元素; Customer对象的orders集合没有被初始化。 |
| 迫切左外连接 | 左外连接查询CUSTOMERS和ORDERS表 | 迫切左外连接检索策略 | 集合中包含Customer类型的元素; 集合中可能有重复元素; Customer对象的orders集合被初始化。 |
| 左外连接 | 左外连接查询CUSTOMERS和ORDERS表 | 延迟检索策略 | 集合中包含对象数组类型的元素,每个对象数组包含一对Customer和Order对象,不同的对象数组可能重复引用同一个Customer对象; Customer对象的orders集合没有被初始化。 |
| 内连接 | 内连接查询CUSTOMERS和ORDERS表 | 延迟检索策略 | 同上 |
| 迫切内连接 | 内连接查询CUSTOMERS和ORDERS表 | 迫切内连接检索策略 | 集合中包含Customer类型的元素; 集合中可能有重复元素; Customer对象的orders集合被初始化。 |
| 右外连接 | 右外连接查询CUSTOMERS和ORDERS表 | 延迟检索策略 | 同左外连接 |
二、投影查询:
投影查询是指查询结果中仅包含部分实体或实体的部分属性。投影式通过select关键字实现的。
实例代码:
//查询结果仅包含Customer对象
select c from Customer c join c.orders o where o.orderNumber like 'T%'
//仅选择对象的部分属性
select c.id,c.name,c.orderNumber from Customer c;
1、动态实例化查询结果:
上面的示例中list()返回的集合存放的是关系数据,而不是对象,可以定义一个类来包装这些属性:
selct new xxx.CustomerBean(c.id, c,name, o.orderNumber) from Customer c join c.orders o where o.orderNumber like 'T%'
2、过滤查询结果中的重复元素:
前面讲过使用Set来过滤重复元素的方式,这里提供例外一种方式:
select distint c.name from Customer c
三、报表查询:
报表查询用于对数据分组和统计,用select关键字选择需要查询的数据,使用group by关键字对数据分组,使用having关键字对分组数据设定约束条件。
HQL语法格式:只有from关键字是必需的。
[select] from ... [where] [group by ... [having...]] [order by...]
1、使用聚集函数:count()\min()\max()\sum()\avg()\
2、分组查询:类似于SQL语句。
3、优化报表查询的性能:主要是考虑查询的报表数据没有必要存放于Session的缓存中。实现方式通过上面获取关系数据的方式即可。
四、高级查询技巧:
概述:
动态查询:在程序运行时动态的决定查询语句的内容。主要通过QBC或QBE实现。
集合过滤:对集合进行过滤,实现对集合的排序、设置约束条件和分页查询等。
子查询:在HQL查询语句中嵌入子查询语句。
本地SQL语句:用本地数据库的SQL方言来查询数据。
查询结果转换器:对查询结果进行过滤或重组,指定查询结果的内容。
1、动态查询:
如果在程序运行前就明确查询语句的内容,优先使用HQL查询方式;若在程序运行时才能明确查询语句的内容时,QBC更加方便。
主要方式是在程序内通过条件判断来决定添加何种查询条件。
2、集合过滤:
通过session.createFilter(customer.getOrders(),"where ...");
第一个参数指定一个持久化对象的集合
第二个参数指定过滤条件,它由合法的HQL查询语句组成。
3、子查询:
HQL支持在where子句中嵌入子查询语句。要求底层数据库支持子查询,例如MySQL从4.1.x才开始支持子查询。
可以使用all\any\some\in\exists关键字。
另外HQL提供了一组操纵集合的函数或者属性:
size()函数或者size属性:获得集合中元素的数目。
minIndex()函数或者minIndex属性:对于建立了索引的集合,获取最小的索引。
maxIndex()函数或者maxIndex属性:对于建立了索引的集合,获取最大的索引。
minElement():对包含基本类型元素的集合,获得集合中取值最小的元素。
maxElement():对包含基本类型元素的集合,获得集合中取值最大的元素。
elements():获得集合中的所有元素。
4、本地SQL查询:
session.createSQLQuery("select * from CUSTOMERS");
若要明确指定每一列的Java数据类型:
addScalar("ID", Hibernate.LONG);
addEntity(Cusmomer.class);把结果集中的关系数据映射为对象。
addJoin():用于连接查询。
上述连接查询方式中,如果在程序代码中直接写SQL语句,会增加维护代码的难度,不建议此种硬编码的方式,替代方案是使用下面的方式:
<sql-query name="findOrderByName">
<return alias="o" class="mypack.Order"/>
<return-join alias="c" property="o.customer"/>
select {o.*},{c.*} from ORDERS o join CUSTOMERS c on o.CUSTOMER_ID=c.ID where c.NAME=:name
</sql-query> Query query = session.getNamedQuery("findOrderByName").setParameter("name","TOM");
List list = query.list();
5、查询结果转换器:
在Criteria中,通过Criteria.setResultTransformer()来指定常量:
Criteria.ROOT_ENTITY:默认值。查询结果中仅包含根节点的实例,可能有重复值。
Criteria.DISTINCT_ROOT_ENTITY:查询结果中仅包含根节点的实例,没有重复值。
Criteria.ALIAS_TO_ENTITY_MAP:查询结果中包含根节点的实例及被关联的实例,存放在Map中。
在HQL检索方式和本地SQL检索方式中,通过setResultTransformer(Transformes.aliasToBean(CustomerDTO.class));
五、查询性能优化:
1、Hibernate优化查询的手段:
A、减低访问数据库的频率,减少select语句的数量。实现手段包括:
1、使用迫切左外连接或者迫切内连接检索策略。
2、对延迟加载或立即检索策略设置批量检索数目。
3、使用查询缓存。
B、避免多余加载程序中不需要访问的数据:实现手段包括:
1、使用延迟加载策略。
2、使用集合过滤。
C、避免报表查询数据占用缓存。实现手段为利用投影查询功能,查询出实体的部分属性。
D、减少select语句中字段的数量,从而减低访问数据库的数据量。
2、iterate()方法:
在启用二级缓存的情况下,可以轻微的提高查询性能。
3、查询缓存:
如果查询结果中包含实体,查询缓存只会存放实体的OID;对于投影查询,查询缓存会存放所有的数据值。
1、适用场合:
A、在应用程序运行时经常使用的查询语句。
B、很少对查询语句检索到的数据进行插入、删除或更新操作。
2、启用查询缓存的步骤:
A、配置第二级缓存。(详见后续的说明)
B、配置查询缓存属性:hibernate.cache.user_query_chche=true
C、对于希望启用查询缓存的查询语句,调用Query接口的setCacheable(true);
D、若希望更加精粒度的控制查询缓存,可以设置缓存区域。详见后续笔记说明。
六、总结:
比较HQL与QBC的优缺点:
| 比较方面 | HQL检索方式 | QBC检索方式 |
| 可读性 | 优点:和SQL语言比较接近,比较容易读懂 | 缺点:QBC把查询语句肢解为一组Criteria实例,可读性差 |
| 功能 | 优点:功能最强大,支持各种连接查询 | 缺点:没有HQL的强大,例如不支持报表查询和子查询,而且对连接查询也做了很多限制 |
| 查询语句形式 | 缺点:应用程序必须提供基于字符串形式的HQL查询语句 | 优点:QBC检索方式封装了基于字符串形式的查询语句,提供了更加面向对象的接口。 |
| 何时被解析 | 缺点:HQL查询语句只有在运行时才会被解析 | 优点:QBC在编译时就能被解析,因此更加容易排错。 |
| 可扩展性 | 缺点:不具有可扩展性 | 优点:允许用户扩展Criteria接口 |
| 对动态查询语句的支持 | 缺点:尽管支持生成动态查询语句,但是编程很麻烦 | 优点:适合于生成动态查询语句 |
攻城狮在路上(壹) Hibernate(十四)--- Hibernate的检索方式(下)的更多相关文章
- 攻城狮在路上(壹) Hibernate(十八)--- 管理Hibernate的缓存
一般Session的缓存被称为Hibernate的第一级缓存,SessionFactory的外置缓存是一个可配置的缓存插件,称为Hibernate的第二级缓存.一.缓存的基本原理: 1.持久化层的缓存 ...
- 攻城狮在路上(壹) Hibernate(十六)--- Hibernate声明数据库事务
一.数据库事务的概念: 数据库的ACID特征:Atomic.Consistency.Isolation.Durability.原子性.一致性.隔离性.持久性.不同的隔离级别引发的不同问题. 事务的AC ...
- 攻城狮在路上(壹) Hibernate(十三)--- Hibernate的检索方式(上)
Hibernate提供了以下几种检索对象的方式: A.导航对象图检索方式. B.OID检索方式.Session.get() load(); C.HQL检索方式.Query. D.QBC检索方式.Que ...
- 攻城狮在路上(壹) Hibernate(九)--- Hibernate的映射类型
Hibernate采用映射类型作为Java类型和SQL类型的桥梁,对应type属性.分为两种:内置映射类型和客户化映射类型.一.内置映射类型: 1.Java基本类型的Hibernate映射类型: Ja ...
- 攻城狮在路上(壹) Hibernate(七)--- 通过Hibernate操纵对象(下)
一.与触发器协同工作: 当Hibernate与数据库的触发器协同工作时,会出现以下两类问题: 1.触发器使Session缓存中的数据和数据库中的不一致: 出现此问题的原因是触发器运行在数据库内,它执行 ...
- 攻城狮在路上(壹) Hibernate(三)--- 属性访问、命名策略、派生属性、指定包名等
一.hibernate访问持久化类属性的策略: 在<property>元素中的access属性用于指定Hibernate访问持久化类属性的方式. 常见的方式如下: 1.property:默 ...
- 攻城狮在路上(壹) Hibernate(二)--- 第一个hibernate程序
1.直接通过JDBC API持久化实体域对象: A.java.sql常用接口和类: DriverManager:驱动程序管理器,负责创建数据库连接. Connection:代表数据库连接. State ...
- 攻城狮在路上(壹) Hibernate(十五)--- Hibernate的高级配置
一.配置数据库连接池: 1.使用默认的数据库连接池: Hibernate提供了默认了数据库连接池,它的实现类为DriverManegerConnectionProvider,如果在Hibernate的 ...
- 攻城狮在路上(壹) Hibernate(十二)--- Hibernate的检索策略
本文依旧以Customer类和Order类进行说明.一.引言: Hibernate检索Customer对象时立即检索与之关联的Order对象,这种检索策略为立即检索策略.立即检索策略存在两大不足: A ...
随机推荐
- COGS 2434 暗之链锁 题解
[题意] 给出一个有n个点的无向图,其中有n-1条主要边且这些主要边构成一棵树,此外还有m条其他边,求斩断原图的一条主要边和一条其他边使得图不连通的方案数. 注意,即使只斩断主要边就可以使得原图不连通 ...
- Linux 查看磁盘空间大小
(1)查看文件大小 1. 查看当前文件夹下所有文件大小(包括子文件夹) du -sh 2.查看var目录下文件大小 du -sh var 3.查看指定文件夹下所有文件大小(包括子文件 ...
- Maven学习总结
转载至:http://www.cnblogs.com/xdp-gacl/p/3498271.html 一 入门 一.Maven的基本概念 Maven(翻译为"专家","内 ...
- JavaScript Window对象属性
window 代表浏览器中一个打开的窗口. Window的属性 属性 描述 closed 获取引用窗口是否已关闭. defaultStatus 设置或获取要在窗口底部的状态栏上显示的缺省信息. dia ...
- Hadoop2.2.0环境下Sqoop1.99.3安装
本文转载自http://blog.csdn.net/liuwenbo0920/article/details/40504045 1.安装准备工作: 已经装好的hadoop环境是hadoop 2.2.0 ...
- JavaBean转换为XML的源码
package com.cmge.utils; import java.util.Iterator; import com.cmge.org.oa.bean.OADepartment; import ...
- POJ 2421(prim)
http://poj.org/problem?id=2421 这个题和poj1258是一样的,只要在1258的基础上那么几行代码,就可以A,水. 题意:还是n连通问题,和1258不同的就是这个还有几条 ...
- 大小端; union
#include<stdio.h> #include <stdlib.h> typedef union { int m; char a[4]; }Node; int main ...
- HBase独立集群部署
HBase是分布式.面向列式存储的开源数据库,来源于Google的论文BigTable,HBase运行于Hadoop平台之上,不同于一般的关系数据库,是一个适合非结构化数据存储的分布式数据库 安装Hb ...
- 3.nodejs权威指南--文件
1. 文件 1.1 读写整个文件 1.1.1 读 var fs = require('fs'); fs.readFile('./test.txt',function(err,data){ if(err ...