攻城狮在路上(壹) 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 ...
随机推荐
- php类与对象
1.类与对象 对象:实际存在该类事物中每个实物的个体.$a =new User(); 实例化后的$a 引用:php的别名,两个不同的变量名字指向相同的内容 封装: 把对象的属性和方法组织在一个类(逻辑 ...
- EXTJS动态改变store的proxy的params
动态改变store的条件参数.var store = win.down('grid[name=sourceGrid]').getStore(); Ext.apply(store.proxy.extra ...
- MFCC可视化
大多数文章和博客介绍都是MFCC的算法流程,物理意义,这里仅仅从数据分布可视化的角度,清晰 观察MFCC特征在空间中的分布情况,加深理解. MFCC处理流程: MFCC参数的提取包括以下几个步骤: 1 ...
- php上传文件大小限制修改
打开php.ini 1.最大上传文件大小: upload_max_filesize=2M 改成自己需要的大小 2.最大post大小: post_max_size=2M 改成自己需要的大小,第二个一般比 ...
- java实现远程储存读取文件
import java.io.BufferedReader;import java.io.BufferedWriter;import java.io.File;import java.io.FileN ...
- Shortest Palindrome
Given a string S, you are allowed to convert it to a palindrome by adding characters in front of it. ...
- freemodbus-v1.5.0 源码分析
注:转载请注明出处 http://www.cnblogs.com/wujing-hubei/p/5935142.html FreeModbus协议栈作为从机,等待主机传送的数据,当从机接收到一帧完 ...
- 【leetcode】Populating Next Right Pointers in Each Node II
Populating Next Right Pointers in Each Node II Follow up for problem "Populating Next Right Poi ...
- Twisted安装
Debian sudo apt-get install gcc python-dev && sudo pip install twisted CentOS sudo yum insta ...
- Unity全屏模糊
先上效果,左边模糊 其实用的是Unity Stard Effect里的资源,一个脚本一个shader //脚本代码 using UnityEngine; using System.Collection ...