首页 > WEB开发 > 后台开发 > HQL和Hibernate性能优化
2014
10-18

HQL和Hibernate性能优化

08. HQL和Hibernate性能优化18

一、HQL简介

HQL(Hibernate Query Language):Hibernate中的查询语言,HQL的语法同SQL非常相似。最大的区别在于HQL被设计为完全面向对象的查询

扩展:常用查询语言

Hibernate 支持强大且易于使用的面向对象查询语言(HQL),如果希望通过编程的方式创建查询,Hibernate 提供了完善的按条件(Query By Criteria,QBC)以及按样例(Query By Example,QBE)进行查询的功能。你也可以用原生 SQL(native SQL)描述查询,Hibernate 额外提供了将结果集(result set)转化为对象的支持。它们的关系也可以表示为:NativeSQL > HQL > EJBQL(JPQL2.0) > QBC > QBE。其中“>”表示前者的功能大于后者,如果用后者没办法实现,可以考虑用前面的。

下面简单说说这几种查询语言:

  • NativeSQL:数据库原生SQL。Hibernate提供了SQLQuery接口,允许开发人员自己编写SQL语句来完成所有的CRUD操作。在程序中可以通过Session.createSQLQuery()获取这个接口,如:

sess.createSQLQuery(“select * from persons”).list();
sess.createSQLQuery(“select name,age,birthday from persons”).list();

两种用法都返回一个 Object 数组(Object[])组成的 List,数组每个元素都是 CATS 表的一个字段值。

关于NativeSQL的详细用法参考Hibernate提供的帮助文档(位于Hibernate/ documentation/ manual目录下)。

  • HQL:Hibernate中提供的查询语言。完全面向对象!Hibernate提供了Query接口和相关API执行HQL语句,Query的实例通过Session.createQuery(String hql)获得。具体用法见第二节。
  • EJBQL(JPQL):JPA查询语言,HQL的一个子集。开发时够用了。
  • QBC:条件查询。具体查文档

二、HQL常见用法

本节用一个Demo将HQL的常见用法串起来。Demo来源于论坛系统中的常见操作,涉及到的类如下图所示:

08. HQL和Hibernate性能优化1033

数据库中对应的表为:category、topic、msg,在每个表中都插入10条数据(用程序模拟出来的),如下:

category-topic-msg-1

1、单表查询(Category表)

1)最基本的查询:

Query query = session.createQuery("from Category");
List<Category> categories = (List<Category>)query.list();
for(Category c : categories) {
	System.out.println(c.getName());
}

2)where子句:from Category c where c.name > ‘c5′

3)order by子句:from Category c order by c.name desc

4)带参数的HQL(比较灵活)

Query query = session.createQuery("from Category c where c.id > :min and c.id < :max");
//query.setParameter("min", 2);
//query.setParameter("max", 8);
query.setInteger("min", 2);
query.setInteger("max", 8);
---------------或者这样写:----------------
Query query = session.createQuery("from Category c where c.id > :min and c.id < :max")
	.setInteger("min", 2)
	.setInteger("max", 8);
---------------也可以这样写:----------------
Query query = session.createQuery("from Category c where c.id > ? and c.id < ?");
query.setParameter(0, 2)
	.setParameter(1, 8);

5)分页查询

Query query = session.createQuery("from Category c order by c.name desc");
query.setFirstResult(2);
query.setMaxResults(4);

6)只查询某些字段

上面的例子都是查询一整个对象,query.list()返回的结果类型为List<Category>。如果只查询某些(个)字段,query.list()返回的结果类型为List<Object[]>。

Query query = session.createQuery("select c.id,  c.name from Category c order by c.name desc");
List<Object[]> categories = (List<Object[]>)query.list();
for(Object[] obj : categories) {
	System.out.println(obj[0] + "-" + obj[1]);
}

7)查询的结果只有一条记录时的简单处理:uniqueResult

Query query = session.createQuery("from Msg m where m.id=1 ");
Msg mResult = (Msg)query.uniqueResult();
System.out.println(mResult.getContent());
---------------再看一个例子:----------------
Query query = session.createQuery("select count(*) from Msg m");
long count = (Long)query.uniqueResult();
System.out.println(count);

2、多表查询(对象间的关联关系)

当涉及到多表的查询时,HQL就要和导航关系结合起来了。当从一个对象A可以访问另外一个对象B时(关联),就称A可以导航到B。如由msg可以导航到topic,由topic可以导航到category。关于对象之间的导航见《OGNL表达式 & ValueStack》一文。

1)查询某个版块下的所有主题:t.category.id=1,导航一次

Query query = session.createQuery("from Topic t where t.category.id = 1");
List<Topic> topics = (List<Topic>)query.list();
for(Topic t : topics) {
	System.out.println(t.getTitle());
}

2)查询某个版块下的所有回复:m.topic.category.id=1,两次导航

Query query = session.createQuery("from Msg m where m.topic.category.id = 1");

for(Object o : query.list()) {
	Msg m = (Msg)o;
	System.out.println(m.getContent());
}

3)得到所有回复的相关信息,封装到MsgInfo对象中:

Query query = session.createQuery("select new org.flyne.domain.MsgInfo(m.id, m.content, m.topic.title, m.topic.category.name) from Msg m");

for(Object o : query.list()) {
	MsgInfo m = (MsgInfo)o;
	System.out.println(m.getContent());
}

4)连接(join)操作

Query query = session.createQuery("select t.title, c.name from Topic t join t.category c "); //join Category c
for(Object o : query.list()) {
	Object[] m = (Object[])o;
	System.out.println(m[0] + "-" + m[1]);
}

在上面join后用的是t.category,而非Category,这是因为:如果在Topic类中定义了两个Category类型的字段,则没办法关联。

总结:

HQL和SQL的语法有很多相似之处,如在HQL的where子句中也可以使用between and、in(…)、is (not) null、like等等,不再一一举例。另外在HQL的where子句还可以使用is (not) empty语法,它与is (not) null的区别如下:

  • is (not) null:表示对象不为null。用于对象中的字段也为对象时。
  • is (not) empty:表示集合不为空。用于对象中的字段为集合,如在Topic类中增加一个Set<Msg> msgs字段,则HQL语句可以写成From Topic t where t.msgs is not empty。

关于HQL更详细的内容参考Hibernate提供的帮助文档。


留下一个回复

你的email不会被公开。