- 译者序
- 前言
- 本书怎么使用
- 本书排版字体约定
- 本书网站
- 致谢
- 第一部分 Hibernate 快速入门
- 第 1 章 安装和设置
- 第 2 章 映射简介
- 第 3 章 驾驭 Hibernate
- 第 4 章 集合与关联
- 第 5 章 更复杂的关联
- 第 6 章 自定义值类型
- 第 7 章 映射标注
- 第 8 章 条件查询
- 第 9 章 浅谈 HQL
- 第二部分 与其他工具的集成
- 第 10 章 将 Hibernate 连接到 MySQL
- 第 11 章 Hibernate 与 Eclipse:Hibernate Tools 使用实战
- 第 12 章 Maven 进阶
- 第 13 章 Spring 入门:Hibernate 与 Spring
- 第 14 章 画龙点睛:用 Stripes 集成 Spring 和 Hibernate
- 附录 A Hibernate 类型
- 附录 B Criteria API
- 附录 C Hibernate SQL 方言
- 附录 D Spring 事务支持
- 附录 E 参考资源
- 作者简介
- 封面介绍
编写 HQL 查询
我们已经演示过,HQL 查询中用到的语法成分会比 SQL 的少点(比如在第 3 章中,我们使用的查询语句通常就省略了"select"子句)。事实上,惟一真正需要指定的内容就是你感兴趣的类。例 9-1 显示了一个最简单的查询,对于取得数据库中所有持久保存的 Track 实例来说,这完全是一种有效的方式。
注意:HQL 代表 Hibernate Query Language。那 SQL 呢?这得看你问的是谁了。
例 9-1:最简单的 HQL 查询
from Track
没什么内容,对吧?这一 HQL 就相当于例 8-1,在那个例子中我们对 Track 类建立了一个条件查询,但没有提供任何查询条件。
默认情况下,Hibernate 会自动“导入”(import)你映射的每个类的名称,这意味着当你想使用一个类时,不必提供完整的包名称,只需要简单的类名就可以了。只要映射的类名称是惟一的,就不需要在查询中使用完整限定的类名(fully qualified class name)。如果你喜欢,当然也可以这么做,本书就是这样做的,目的是帮助读者记住查询是按照 Java 数据 bean 及其属性来表示的,而并非数据表和字段(在 SQL 查询中使用这些)。例 9-2 的结果和第一个查询的结果完全相同。
例 9-2:显式指定包名,但依然相当简单
from com.oreilly.hh.data.Track
如果需要映射的多个类具有相同的名称,你可以用完全限定的包名来引用每个类,也可以在其映射文件中使用 import 标签为该类或多个类指定替换名称。还可以在映射文件中为最顶层的 hibernate-mapping 标签属性添加一个 auto-import=false 设置,以关掉自动导入(auto-import)的功能。
你可能已经习惯编写查询语句时不区分大小写,因为 SQL 的行为就是如此。大多数时候,HQL 也是如此。但是类和属性的名称显然是例外。和 Java 的其他组成部分一样,它们是区分大小写的,所以你得把大小写弄对。
让我们看一个极端的示例,它把 HQL 的多态(polymorphic)查询能力推向它的逻辑上的极限,以此来了解 HQL 和 SQL 究竟在哪不同。
应该怎么做
突出 SQL 和 HQL 基本差别的最有效方式就是,考虑当以"from java.lang.Object"来进行查询时会发生什么事。乍一看,可能看不出什么意义!事实上,Hibernate 能够支持返回多态结果的查询。如果映射到的类之间是彼此继承的,或者有共同的基类或接口,那么无论是否将这些类映射到相同的数据表或不同的数据表,都可以查询到它们的超类(superclass)。由于每个 Java 对象都继承自 Object,所以这样的查询就等于要求 Hibernate 返回数据库里的每个实体。我们可以对查询测试做个快速的修改,以测试一下这一查询。把 QueryTest.java 复制成 QueryTest3.java,按例 9-3 所示的内容对它进行修改(大多数修改都是将这里不需要的示例查询删除掉,所以例 9-3 中看不到那些被删除的部分)。
如果你正在使用 Eclipse,那么可以直接跳到第 11 章,阅读有关 Hibernate Tools 的章节,再回来继续学习本章的内容。那一章介绍的 HQL Editor 是一个非常方便的工具,可以帮助你处理我们需要查看的各种查询。用它来做实验太有效了,可以接合你自己的修改,帮助你更深入地学习 HQL。
例 9-3:看吧,再也不用 SQL 了
package com.oreilly.hh;
import org.hibernate.*;
import org.hibernate.cfg.Configuration;
import org.hibernate.criterion.*;
import com.oreilly.hh.data.*;
import java.util.*;
/**
*Retrieve all persistent objects
*/
public class QueryTest3{
/**
*Look up and print all entities when invoked from the command line.
*/
public static void main(String args[])throws Exception{
//Create a configuration based on the properties file we've put
//in the standard place.
Configuration config=new Configuration();
config.configure();
//Get the session factory we can use for persistence
SessionFactory sessionFactory=config.buildSessionFactory();
//Ask for a session using the JDBC information we've configured
Session session=sessionFactory.openSession();
try{
//Print every mapped object in the database
List all=session.createQuery("from java.lang.Object").list();❶
for(Object obj:all){
System.out.println(obj);❷
}
}finally{
//No matter what, close the session
session.close();
}
//Clean up after ourselves
sessionFactory.close();
}
}
❶这行简单的代码就调用了奇妙而功能强大的 HQL 查询。
❷接下来所有需要做的就是循环遍历和打印输出我们找到的结果。除了调用取回的对象的 toString()方法以外,我们什么也不能做,因为我们不知道它们是什么类。作为共享接口,Object 没有提供非常深入的方法。
在运行这个示例之前,还得再多做一件事。在 build.xml 中添加另一个构建目标,如例 9-4 所示。
和以前一样,假设你已经按照前面章节的说明搭建好了环境。也可以直接下载使用为这一章提供的示例源代码。如果你从第 7 章过来,将映射文档换成了标注,则要么你需要回到第 6 章的源代码,要么重新下载本章的源代码,因为本章的这些示例需要依靠映射文件的功能。
例 9-4:调用这个特殊查询
<target name="qtest3"description="Retrieve all mapped objects"
depends="compile">
<java classname="com.oreilly.hh.QueryTest3"fork="true">
<classpath refid="project.class.path"/>
</java>
</target>
为了确保创建好所有的样例数据,先要运行 ant schema ctest atest 命令。接着,再执行 ant qtest3 命令以测试新的查询,得到的结果如例 9-5 所示。
例 9-5:Hibernate 能找到一切事物
%ant qtest3
Buildfile:build.xml
prepare:
usertypes:
codegen:
[hibernatetool]Executing Hibernate Tool with a Standard Configuration
[hibernatetool]1.task:hbm2java(Generates a set of.java files)
compile:
[javac]Compiling 4 source files to/Users/jim/Documents/Work/OReilly
/svn_hibernate/current/examples/ch09/classes
qtest3:
[java]com.oreilly.hh.data.Artist@8a137c[name='PPK'actualArtist='null']
[java]com.oreilly.hh.data.Artist@79e4c[name='The Buggles'actualArtist='n
ull']
[java]com.oreilly.hh.data.Artist@29ae5e[name='Laurie Anderson'actualArti
st='null']
[java]com.oreilly.hh.data.Artist@76a9b6[name='William Orbit'actualArtist
='null']
[java]com.oreilly.hh.data.Artist@801919[name='Ferry Corsten'actualArtist
='null']
[java]com.oreilly.hh.data.Artist@efe4ac[name='Samuel Barber'actualArtist
='null']
[java]com.oreilly.hh.data.Artist@8e13ab[name='ATB'actualArtist='null']
[java]com.oreilly.hh.data.Artist@ad44f6[name='Pulp Victim'actualArtist
='null']
[java]com.oreilly.hh.data.Artist@8aaed5[name='Martin L.Gore'actualArtist
='null']
[java]com.oreilly.hh.data.Album@a1644b[title='Counterfeit e.p.'tracks='[
com.oreilly.hh.data.AlbumTrack@132f26[track='com.oreilly.hh.data.Track@d8f246[
title='Compulsion'volume='Volume[left=100,right=100]'sourceMedia='CD']'],c
om.oreilly.hh.data.AlbumTrack@5ae101[track='com.oreilly.hh.data.Track@9eab7[ti
tle='In a Manner of Speaking'volume='Volume[left=100,right=100]'sourceMedia='
CD']'],com.oreilly.hh.data.AlbumTrack@6a16ae[track='com.oreilly.hh.data.Trac
k@10cf62[title='Smile in the Crowd'volume='Volume[left=100,right=100]'source
Media='CD']'],com.oreilly.hh.data.AlbumTrack@f7309a[track='com.oreilly.hh.da
ta.Track@9f332b[title='Gone'volume='Volume[left=100,right=100]'sourceMedia='
CD']'],com.oreilly.hh.data.AlbumTrack@97cf78[track='com.oreilly.hh.data.Trac
k@d86cae[title='Never Turn Your Back on Mother Earth'volume='Volume[left=100,
right=100]'sourceMedia='CD']'],com.oreilly.hh.data.AlbumTrack@b5d53a[track=
'com.oreilly.hh.data.Track@c74b55[title='Motherless Child'volume='Volume[left=
100,right=100]'sourceMedia='CD']']]']
[java]com.oreilly.hh.data.Track@e74d83[title='Russian Trance'volume='Vol
ume[left=100,right=100]'sourceMedia='CD']
[java]com.oreilly.hh.data.Track@5d8362[title='Video Killed the Radio Star
'volume='Volume[left=100,right=100]'sourceMedia='VHS']
[java]com.oreilly.hh.data.Track@5c9ab5[title='Gravity's Angel'volume='Vo
lume[left=100,right=100]'sourceMedia='CD']
[java]com.oreilly.hh.data.Track@b0e76a[title='Adagio for Strings(Ferry C
orsten Remix)'volume='Volume[left=100,right=100]'sourceMedia='CD']
[java]com.oreilly.hh.data.Track@28ea3f[title='Adagio for Strings(ATB Rem
ix)'volume='Volume[left=100,right=100]'sourceMedia='CD']
[java]com.oreilly.hh.data.Track@2af08b[title='The World'99'volume='Volu
me[left=100,right=100]'sourceMedia='STREAM']
[java]com.oreilly.hh.data.Track@164feb[title='Test Tone 1'volume='Volume
[left=50,right=75]'sourceMedia='null']
[java]com.oreilly.hh.data.Track@d8f246[title='Compulsion'volume='Volume[
left=100,right=100]'sourceMedia='CD']
[java]com.oreilly.hh.data.Track@9eab7[title='In a Manner of Speaking'vol
ume='Volume[left=100,right=100]'sourceMedia='CD']
[java]com.oreilly.hh.data.Track@10cf62[title='Smile in the Crowd'volume=
'Volume[left=100,right=100]'sourceMedia='CD']
[java]com.oreilly.hh.data.Track@9f332b[title='Gone'volume='Volume[left=1
00,right=100]'sourceMedia='CD']
[java]com.oreilly.hh.data.Track@d86cae[title='Never Turn Your Back on Mot
her Earth'volume='Volume[left=100,right=100]'sourceMedia='CD']
[java]com.oreilly.hh.data.Track@c74b55[title='Motherless Child'volume='V
olume[left=100,right=100]'sourceMedia='CD']
BUILD SUCCESSFUL
Total time:9 seconds
发生了什么事
嗯,仔细想一想,这可真不简单,因为 Hibernate 得分别做好几次 SQL 查询才能获得我们想要的所有结果。Hibernate 在幕后做了很多工作,才能把每个它知道的持久化实体的列表交给我们。虽然很难想象实际需要这么做的情况,但这确实突出了 HQL 和 Hibernate 有趣的能力所在。
有时候某些查询确实有些难以理解,但却非常有用。所以记住这一点很有价值:跨表的多态查询(polymorphic query)不仅可行,而且容易使用。
当你执行需要多条 SQL 查询才能完成的 HQL 查询时,会有些限制需要注意。不能使用 order by 子句对整个结果集进行排序,也不能使用 Query 接口 scroll()方法遍历整个结果集。
其他
关联(association)和连接(join)呢?这些也容易处理。只要使用点号作为分隔符(delimiter),顺着属性链走,就能访问关联对象。为了帮助你引用查询表达式中的特定实体,HQL 可以让你指定别名(就像 SQL 一样)。如果你想引用同一个类的两个不同的实体,别名就特别重要,例如:
from com.oreilly.hh.Track as track1
相当于:
from com.oreilly.hh.Track track1
采用哪一种方法取决于你的习惯,或者取决于你为项目准备的编码风格指南。
我们对其他 HQL 元素进行了足够的介绍,就是想让它们吸引起你的兴趣。稍后我们会看看一些连接的示例。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论