Hibernate的查询语言之HQL(二)——Hibernate查询的from字句
from 是最简单的HQL语句,也是最基本的HQL语句。from 关键字后紧跟持久化类的类名。例如:
from Person
表明从Person持久化类中取出全部的实例。
大部分时候,推荐位该Person的每个实例取一个别名。例如:
from Person as p
上面的as是可选的,但为了增加可读性,建议保留。
from 后面还可以同时出现多个持久化类,此时将产生一个笛卡尔积或跨表连接,但实际上这种用法很少使用,因为通常我们可能需要使用跨表连接时,可以考虑使用隐士连接或者显示连接,而不是直接在from后紧跟多个表名。
关联和连接
当程序需要从多个数据表中取得数据时,SQL语句将会考虑使用多表连接查询。Hibernate使用关联映射来处理底层数据表之间的连接,一旦我们提供正确的映射后,当程序通过Hibernate进行持久化访问时,将可利用Hibernate的关联进行连接。
HQL支持两种关联连接(join)形式: 隐式(implicit)与显式(explicit)。
隐式连接形式不适用 join 关键字,使用英文点号(.)来隐式连接关联实体,而Hibernate底层将自动进行关联查询。例如如下HQL语句
//查询Person持久化实体
from Person as p
where p.myEvents.titile > :title
上面的p.myEvents属性的实质是一个持久化实体,因此Hibernate底层隐式自动进行连接查询。
显式连接则需要使用 xxx join 关键字。例如下面的语句:
from Person p
inner join p.myEvents event
where event.happenDate < :endDate
使用显式连接 时可以为相关联的实体,甚至是关联集合中的全部元素指定一个别名。
Hibernate支持的HQL连接直接借鉴了 SQL99 多表查询的关键字,可使用如下几种连接方法。
》inner join (内连接),可简写成 join。
》left outer join(左外连接),可简写成 left join。
》right outer join(右外连接),可简写成right join。
》full join(全连接),并不常用。
使用显式连接时,还可通过HQL的with关键字来提供额外的连接条件,例如如下HQL语句:
from Person p
inner join p.myEvents event
with p.id > event.id
where event.happenDate < :endDate
Hibernate会将这种显式连接转换成SQL99多表连接的语法,所以HQL语句中with关键字的作用等同于SQL99中 on 关键字的作用;都是用于指定连接条件。通过在HQL语句中使用with关键字,可以让HQL语句执行非等值连接查询。
不难发现 要想完全掌握HQL,不懂SQL是完全不行的。
还有一点必须指出:由于此处的inner join, left join, right join, full join的实质依然是基于底层的SQL的内,左,外连接的,所以如果底层SQL不支持这些外连接,那么执行相应的HQL时就会相应的引发异常。
对于隐式连接和显式连接还有如下两点区别:
》隐式连接底层将转换为SQL99 的交叉连接,显式连接底层将转换成SQL99 的 inner join, left join, right join等连接。
对于from Person p where p.myEvent.title > :title这条隐式连接的HQL语句,执行HQL查询后将看到产生如下所示的SQL语句。
select
person0_.person_id as person1_0_,
person0_.name as name_0,
person0_.age as age0_,
person0_.event_id as event4_0_
from
person person0_ cross
join
event myevent1_
where
person0_.event_id = myevent1_.event_id
and myevent1_.title > ?
而对于from Person p left join p.myEvents event where event.happenDate < :endDate 这条显式连接的HQL语句,执行HQL查询后将看到产生如下所示的SQL语句:
select
person0_.person_id as person1_0_,
person0_.name as name0_,
person0_.age as age0_,
person0_.event_id as event4_0_
from person person0_
left outer join
event myevent1_
on person0_.event_id = myevent1_.event_id
where
myevent1_.happenDate < ?
对比这两条SQL语句,不难发现第一条SQL语句是SQL99的交叉连接,而第二条SQL语句则是SQL99的左外连接语法——具体到底使用哪种连接方法,取决于HQL语句的显示连接使用了哪种连接方式。
》隐式连接和显示连接查询后返回的结果不同。
当HQL语句中省略select关键字时,使用隐式连接查询返回的结果是多个被查询实体组成的集合。如上面第一条SQL语句所示,它只选择person表中的数据列,所以查询得到的结果是Person对象组成的集合。
当使用显式连接查询的HQL语句中省略select关键字时,返回的结果也是集合,但集合元素是被查询持久化对象,所有被关联的持久化对象所组成的数组。如上面的第二条SQL语句所示,他同时选择了person,event表中的所有数据列,查询得到的结果集的每条记录即包含了Person实体的全部属性,也包含了MyEvent实体的全部属性。Hibernate会把每条记录封装成一个集合元素,用属于Person的属性创建Person对象,属于MyEvent的属性创建MyEvent对象.....多个持久化实体最后封装成一个数组来作为集合元素。
如:
Session session = HibernateSessionFactory.getSession();
Transaction tx = session.beginTransaction();
String hql = "from Person p join p.myEvents event";
List<Object[]> datas = session.createQuery(hql).list();
for(Object[] data:datas){
System.out.println(data[0]);//输出Person持久化实体对象
System.out.println(data[1]);//输出MyEvent持久化实体对象
}
tx.commit();
session.close();
关于隐式连接和显示连接还有非常主要的一点需要指出,这是由Hibernate版本升级所引发的问题。在Hibernate3.2.2之前的版本, Hibernate会对所有关联实体自动使用隐式连接。对于如下HQL语句:
from Person p
where p.myEvents.title = :eventTitle
无论如何, Hibernate将对上面的p.myEvents.title自动使用隐式连接,因此上面的HQL语句总是有效的。
从Hibernate3.2.3以后, Hibernate改变了这种隐式连接的策略,还是对于这条同样的HQL语句,则可能出现以后几种情况:
》如果myEvents 是普通组件属性,或单个的关联实体,则Hibernate会自动生成隐式内连接,上面的HQL语句依然有效。
》如果myEvents是一个集合(包括1-N,N-N关联),那么系统将出现:QueryException异常,异常提示信息为:
org.hibernate.QueryException: illegal attempt to dereference collection
根据Hibernate的官方说法:这样可以使的隐式连接更具确定性(原文:This makes implicit joins more deterministic)
为此, Hibernate推荐上面的HQL语句写成:
from Person p
inner join p.myEvents e
where e.title = :eventTitle
这条HQL语句将会返回一个集合,集合元素是Person实体和MyEvent实体组成的数组。
如果只想获取Person组成的集合,则需要改写成:
select p
from Person p
join p.myEvents e
where e.title = :eventTitle
但上面的语句可能返回多个完全相同的Person对象,想一想SQL多表连接查询的结果就可知道原因了。
如果想得到由Person实体组成的集合,且元素不重复,应该改为如下SQL语句:
select distinct p
from Person p
inner join p.myEvents e
where e.title = :eventTitle
也就是说,对于Hibernate 3.2.3以后的版本,如果关联实体是单个实例或单个的组件属性,HQL依然可以可以使用英文句点(.)来隐式连接关联实体或组件;但如果关联实体是集合(包括1-N关联,N-N关联和集合元素是组件等),则必须使用 xxx join 来显式连接关联实体或组件。
对于有集合属性的,Hibernate默认采用延迟加载策略。如果Session被关闭,Person实例将无法访问关联的scores属性。
为了解决该问题,可以在Hibernate映射文件中指定 lazy = "false" 来关闭延迟加载。
还有一种方法,使用join fetch,例如:
from Person p
join fetch p.scores
上面的关键字将导致Hibernate在初始化Person对象时,同时抓取该Person关联的scores集合属性。
使用join fetch时通常无需指定别名,因为相关联的的对象不应在where字句(或其他任何字句)中使用。而且被关联的对象也不会再被查询的结果中直接返回,而是应该通过其父对象来访问。
使用fetch关键字时有如下几个注意点
》fetch不应该与setMaxResult()或setFirstResult()公用。因为这些操作都是基于结果集的,而在预先抓取集合类时可能包含重复的数据,即无法预先知道精确的行数。
》fetch不能独立与with条件一起使用。
》如果在一次查询中fetch多个集合,可以查询返回笛卡尔积,因此请多加注意。
》对bag映射而言,同时join fetch多个集合可能出现非预期结果,因此需要谨慎使用。
》full join fetch 与 right join fetch是没有任何意义的。
如果在映射文件映射属性时同时指定 lazy = "true" 启动了延迟加载(这种延迟加载是通过字节码增强来实现的),然后程序里有希望预加载那些原本应延迟加载的属性,则可以通过 fetch all properties 来强制Hibernate立即抓取这些属性。例如:
from Document fetch all properties order by name
from Document doc fetch all properties where lower(doc.name) like '%cats%'
Hibernate的查询语言之HQL(二)——Hibernate查询的from字句的更多相关文章
- Hibernate的查询语言之HQL(一)——快速入门
Hibernate提供异常强大的查询体系,使用Hibernat有多种查询方式可以选择:即可以使用Hibernate的HQL查询,也可以使用条件查询,甚至可以使用原生的SQL查询语句.不仅如此, Hib ...
- J2EE进阶(十七)Hibernate中常用的HQL查询方法(getHibernateTemplate())
J2EE进阶(十七)Hibernate中常用的HQL查询方法(getHibernateTemplate()) 当我们使用Hibernate进行数据的CRUD操作时,利用模版进行操作不失为一种方法. ...
- Hibernate hql(hibernate query language)基础查询
在开发过程中,数据库的操作我们其实更多的用到的是查询功能,今天开始学习hql的查询. 1.加入必要的工具 2.Hibernate配备的一种非常强大的查询语言,这种查询语言看上去很像sql.但是不要被语 ...
- Hibernate查询语言(HQL)
Hibernate查询语言(HQL)与SQL(结构化查询语言)相同,但不依赖于数据库表. 我们在HQL中使用类名,而不是表名. 所以是数据库独立的查询语言. HQL的优点 HQL有很多优点. 它们如下 ...
- hibernate学习系列-----(4)hibernate基本查询上篇:HQL基本查询
紧接着上一篇,今天继续hibernate的学习总结,来聊一聊hibernate的基本查询方法,先说说HQL(hibernate Query Language):它是官方推荐的查询语言.在开始写代码之前 ...
- Java进阶知识13 Hibernate查询语言(HQL),本文以hibernate注解版为例讲解
1.简单概述 1.1. 1) SQL:面向的是数据库 select * from tableName;2) HQL查询(Hibernate Query language): hibernate 提供的 ...
- java:Hibernate框架3(使用Myeclipse逆向工程生成实体和配置信息,hql语句各种查询(使用hibernate执行原生SQL语句,占位符和命名参数,封装Vo查询多个属性,聚合函数,链接查询,命名查询),Criteria)
1.使用Myeclipse逆向工程生成实体和配置信息: 步骤1:配置MyEclipse Database Explorer: 步骤2:为项目添加hibernate的依赖: 此处打开后,点击next进入 ...
- Hibernate HQL多表查询
1.内连接和迫切内连接 (1)内连接 HQL语句:from 实体类名 实体类别名 inner join 实体类别名.表示另一个表数据的集合名称 (2)迫切内连接 HQL语句:from 实体类名 实体类 ...
- Hibernate的HQL多表查询
HQL的内连接查询 对于HQL内链接查询,查询的是两张表的数据,这两张表的数据首先是保存在数组之中,然后在将每一个数组保存在List集合之中进行返回 代码片段: @Test // 内连接 public ...
随机推荐
- angularJS 指令二
指令详解1.用directive()方法来定义指令.directive('myDirective',function($timeout,userDefinedService){ return {};} ...
- Android Dialog触摸对话框外部让其消失的实现方法
方法一: @Override public boolean onTouchEvent(MotionEvent event) { if (event.getAction() == MotionEvent ...
- UVA 10668 - Expanding Rods(数学+二分)
UVA 10668 - Expanding Rods 题目链接 题意:给定一个铁棒,如图中加热会变成一段圆弧,长度为L′=(1+nc)l,问这时和原来位置的高度之差 思路:画一下图能够非常easy推出 ...
- 解决Xcode6.0.1编译Unity3Dproject报错
错误信息大概例如以下 Undefined symbols for architecture i386: "_clock$UNIX2003",.....等 大概就是引用了一个链接库出 ...
- android中的Handler和Runnable
最近在做一个项目,在网络请求时考虑用Handler进行处理,然后就研究了一下Handler和Runnable 首先在看一下java中的Runnable The Runnable interface s ...
- yii自动登陆的验证机制浅析
一直在使用yii进行开发, 也知道如何去使用, 也仅仅是知道怎么去用罢了, 终归是没研究过源码, 心里发虚, 今天遇到一个问题, 关于自动登陆的问题. 要求就是, 修改登陆保存session天数为自定 ...
- windows服务(Windows Installer问题,错误5:拒绝访问)
Windows Installer问题,错误5:拒绝访问 shillan,2006-11-03 09:40:38 现象: 使用MSI文件来安装的软件在安装和卸载时系统提示:“不能访问Windows I ...
- Linq101-Projection
using System; using System.Linq; namespace Linq101 { class Projection { /// <summary> /// This ...
- 关于IO学习的几个函数
这是最近学到的几个关于IO文件操作的几个小算法,今天总结出来. 1. 删除一个给定的目录,这上目录不为空目录,使用递归来实现 public void test04(File file) { File[ ...
- dbms_job dbms_scheduler简单比较
---------------------------陈旧的-------------------------------------/*--------------------- 创建job --- ...