返回介绍

编写原生 SQL 查询

发布于 2025-04-21 21:42:14 字数 4601 浏览 0 评论 0 收藏

HQL 的功能强大、使用方便,而且能和 Java 代码中的对象自然地结合起来,既然如此,有什么理由不去用 HQL 呢?嗯,项目所用的数据库可能有某些特殊功能是它原生(native)的 SQL 方言才支持的,这时就不能用 HQL 了。如果你愿意接受使用原生 SQL 会让以后数据库的更换变得更加困难的事实,Hibernate 还是可以让你使用这种原生 SQL 方言来编写查询,同时仍然帮助你以对象属性的方式来编写表达式,并把查询结果转换成对象(当然,如果你不想依靠 Hibernate 的帮助,也可以使用原始的 JDBC 连接来执行普通的 SQL 查询)。

另一种可能不完全符合你的情况是,你正处于将当前现有的基于 JDBC 的项目移植到基于 Hibernate 的过程中,而你只是想先前进几小步,并不想立刻彻底重新改写每个查询。

应该怎么做

如果准备将查询语句的文本嵌入到 Java 源代码中,可以用 Session 类的 createSQLQuery()方法,而不是用例 3-7 的 createQuery()方法。当然,你应该知道有比这种编码方式更好的办法,所以我就不举例说明这种方法了。比较好的做法是把查询语句放在映射文档中,如例 3-11 所示。区别在于,现在应该使用<sql-query>标签,而不是我们一直在用的 query 标签。你也需要告诉 Hibernate 要返回什么映射类,以及在查询中引用该类(及其属性)的别名是什么。

假设我们想知道所有恰好结束在半分钟的曲目(换句话说,自动唱片机系统显示的播放时间是 h:mm:30),不过,这个例子有点做作。简单的方法就是使用 HSQLDB 内建的 SECOND 函数,它会返回 Time 值中秒数的部分。由于 HQL 不知道 HSQLDB SQL 方言中这一特殊的函数,所以我们只得使用原生的 SQL 查询。例 9-23 演示了这个例子的实现,将它添加到 Track.hbm.xml 中的 HQL 查询之后。

例 9-23:在 Hibernate 映射文档中嵌入一个原生的 SQL 方言查询

<sql-query name="com.oreilly.hh.tracksEndingAt">

<return alias="track"class="com.oreilly.hh.data.Track"/>

<![CDATA[

select{track.*}

from TRACK as{track}

where SECOND({track}.PLAYTIME)=:seconds

]]>

</sql-query>

return 标签是告诉 Hibernate,我们准备在查询中使用 track 别名来引用 Track 对象,这样就能够在查询语句中使用简写的{track.*}来引用 TRACK 数据表中所需要的所有字段以创建 Track 实例(注意,在查询语句中这样使用别名时必须用大括号将别名括起来。这能让我们“脱离”原生的 SQL 语句环境,用 Hibernate 映射类和属性来描述查询内容)。

查询中的 where 子句使用了 HSQLDB SECOND 函数来过滤查询结果,只在结果中保留时间长度值的秒数部分具有特定值的曲目。幸好,即便我们构建了一个原生的 SQL 查询,依然能够利用 Hibernate 很棒的命名查询参数。在这个示例中,我们传递了一个名为"seconds"的值以控制查询返回的结果。(即便在 SQL 查询中,也不需要使用大括号来告诉 Hibernate 你正在使用命名参数。Hibernate 的解析器足够智能,以致于可以自动明白你写的是什么。)

使用该映射 SQL 查询的代码和前面示例中使用 HQL 查询的代码并没有什么不同。可以用 getNamedQuery()方法来加载这两种查询,而且这两种查询都实现了 Query 接口。所以,调用该查询的 Java 方法看起来应该很熟悉。将例 9-24 中的代码添加到 QueryTest.java 中 printTrackSummary()方法的后面。

例 9-24:调用原生的 SQL 映射查询

/**

*Print tracks that end some number of seconds into their final minute.

*

*@param seconds, the number of seconds at which we want tracks to end.

*@param session the Hibernate session that can retrieve data.

**/

public static void printTracksEndingAt(int seconds, Session session){

Query query=session.getNamedQuery("com.oreilly.hh.tracksEndingAt");

query.setInteger("seconds",seconds);

List results=query.list();

for(ListIterator iter=results.listIterator();iter.hasNext();){

Track track=(Track)iter.next();

System.out.println("Track:"+track.getTitle()+

",length="+track.getPlayTime());

}

}

最后,在 main()中加上几行代码以调用这个方法。例 9-25 演示了将其添加到对 printTrackSummary()的调用之后的样子。

例 9-25:调用 printTracksEndingAt()以显示终止于半分钟的曲目

……

printTrackSummary(CreateTest.getArtist("Samuel Barber",

false, session),session);

System.out.println("Tracks ending halfway through final minute:");

printTracksEndingAt(30,session);

}finally{

//No matter what, close the session

……

执行 ant qtest 命令后,这些修改会产生额外的输出结果,如例 9-26 所示。

例 9-26:原生 SQL 查询的输出示范

qtest:

[java]Track:Video Killed the Radio Star[ID=2]

……

[java]Summary of tracks by Samuel Barber:

[java]Total tracks:2

[java]Shortest track:00:06:35

[java]Longest track:00:07:39

[java]Tracks ending halfway through final minute:

[java]Track:Russian Trance, length=00:03:30

BUILD SUCCESSFUL

Total time:10 seconds

与 HQL 查询相比,使用原生 SQL 查询时需要注意更多不同层次上的细节,也更乏味(尤其是当你的查询变得复杂或涉及对多个数据表的引用时),但是,它偶尔会在某些场合真的可以派上用场,这也是一件好事。

其他

从 Hibernate 3 起,sql-query 映射也成为在 Hibernate 中操纵数据库存储过程的入口点(如果这些与你没什么关系,不必担心;这只是意味着你现在还不需要为它们操心,当你需要使用它们时,就会知道是怎么回事了)。对于可以调用的查询的种类,以及查询可以返回的类型,都有一些明确的限制,而且这些限制会随着数据库的不同而有所不同。更详尽的细节,可以查看 Hibernate 参考手册( [1] )。

嗯,还有其他的东西吗?你会怀疑本章几乎没有谈到用 HQL 可以做些什么。的确如此。当你开始结合这些功能,并运用集合、关联以及功能强大的表达式时,就能完成一些令人刮目相看的事情。我们不可能在这本介绍性的图书中涉及方方面面的细节,所以你得自己去阅读 Hibernate 参考手册中有关 HQL 的那一节及其示例,然后再自己做些实验。

当你阅读 Hibernate 参考手册中有关"Hibernate Query Language"( [2] )的那一章时,一定要看看表达式中能用到的那些有趣的事项,尤其是与集合有关的情况。别忘了你可以用数组括号表示法来选择集合中具有特定索引值的元素,甚至可以在括号中置入算术表达式。Hibernate 参考手册的 HQL 那一章在冗长的示例之后,接着的一节是“小技巧和小窍门”(Tips and Tricks),这一节给出了一些有用的建议,谈到了如何在不同数据库环境中有效地工作,以及使用各种 Hibernate 接口来达到你想都想不到的效果(如果你有 SQL 使用基础,就更是如此)。你也可以仔细研读本书附录 E 提到的那些图书。希望这里的讨论能够帮助你奠定好基础,并能作为日后探索研究的出发点、支柱以及动机!

注意:这不是你老爸那个时代的 SQL……

[1] http://www.hibernate.org/hib_docs/v3/reference/en/html_single/#sp_query. [2] http://www.hibernate.org/hib_docs/v3/reference/en/html/queryhql.html.

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。