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 ...
随机推荐
- AbpZero--4.不使用谷歌字体,提升加载速度
jtable控件样式中会使用到谷歌字体,每次访问都特别慢 1.打开jtable.css文件 [..\MyCompanyName.AbpZeroTemplate.Web\libs\jquery-jtab ...
- 解决python “No module named pip”
python 升级后导致不能使用原来的pip命令 windows平台 cmd中敲命令:python -m ensurepip 得到pip的setuptools 然后就可以用:easy_install ...
- 《Java 并发编程实战》读书笔记之二:图文讲述同步的另一个重要功能:内存可见性
转载请注明出处:http://blog.csdn.net/ns_code/article/details/17288243 加锁(synchronized同步)的功能不仅仅局限于互斥行为,同时还存在另 ...
- PHP安全编程:shell命令注入(转)
使用系统命令是一项危险的操作,尤其在你试图使用远程数据来构造要执行的命令时更是如此.如果使用了被污染数据,命令注入漏洞就产生了. exec()是用于执行shell命令的函数.它返回执行并返回命令输出的 ...
- PHPExcel讀取excel數據
require_once 'PHPExcel.php'; $PHPReader = new PHPExcel_Reader_Excel2007(); $filePath = 'wjyl.xlsx'; ...
- JDK5-静态导入
import static 1. 导入一个类内所有静态成员 import static java.lang.Math.*; public class StaticImport { public sta ...
- Facade 门面模式 外观模式
简介 作用: (1)封装一组交互类,一致地对外提供接口 (2)封装子系统,简化子系统调用 JDK中体现:java.util.logging包 java.lang.Class javax.faces.w ...
- 超级钢琴 2010年NOI
/* 自己yy的奇葩做法居然A了23333 不过空间好像很大 时间好像略慢..... 毕竟不是正解 前缀维护sum值 枚举区间起点 然后终点的坐标可以确定在一个范围 可持久化线段树查询区间第1大 然后 ...
- js正则表达式验证大全
/判断输入内容是否为空 function IsNull(){ var str = document.getElementById('str').value.trim(); ...
- Linux和windows下清除svn保存的账号密码信息
linux是什么用户登录就是什么用户的home下,如root用户就是/root,如果xiangdong就是/home/xiangdong 用Svn时会有一种需求是需要换个帐号测试一下什么的,但往往有缓 ...