您的位置:首页 > 其它

Hibernate之hql语句查询

2015-01-22 22:09 267 查看
   本篇博客主要介绍Hibernate中的HQL查询语句,HQL检索语言类似于SQL语言,以面向对象的方式从数据库中检索信息,当然,HQL语言可以查询具有继承,多态和关联关系的数据。HQL语言查询分为简单属性查询,实体对象查询,条件查询,分页查询和连接查询等等,下面我们分别介绍如何使用HQL语言查询数据。

  实例的背景我们以班级和学生这种一对多的关系为例:

一、简单属性查询

 1、单一属性查询:

List students=session.createQuery("select name from Student").list();
   返回结果集的属性列表,元素类型和实体类中的属性类型一致。createQuery()方法被封装到session中,使用它的时候会创建一个新的Query接口,在方法中我们需要查询字符串作为参数,然后将查询的结果返回到List中。另外对于Hibernate支持原生sql,同样也是创建Query接口,使用createSQLQuery()方法。

 2、多个属性查询:

List students=session.createQuery("select id, name from Student").list();

   多个属性查询,多个属性查询返会对象数组,对象数组的长度取决于属性的个数对象数组中元素的类型取决于属性在实体类中的类型。

   如果认为返会数组不够对象化,可以使用hql动态实例化Student对象,需要在返回的student类中提供一个构造函数:

/**
* 默认的构造函数
* @author xiao
*
*/
public Student(){

}

<span style="white-space:pre">	</span>/**
<span style="white-space:pre">	</span> * 带参数的构造函数,因为查询的时候要返回Student实体
<span style="white-space:pre">	</span> * @author xiao
<span style="white-space:pre">	</span> *
<span style="white-space:pre">	</span> */
<span style="white-space:pre">	</span>public Student(int id, String name) {
<span style="white-space:pre">	</span>this.id = id;
<span style="white-space:pre">	</span>this.name = name;
<span style="white-space:pre">	</span>}

  查询语句如下:

List students=session.createQuery("select new Student(id,name) from Student").list();

 
二、实体对象查询:

  实体对象的查询返回的是一个实体,在查询语句中可以忽略select关键字,如下:

List students=session.createQuery("from Student").list();

  当然也可以使用别名:

List students=session.createQuery("from Student s").list();

  但是如果加上了select关键字,则必须使用别名的方式编写查询语句:

List students=session.createQuery("select s from Student s").list();

  另外,hql不支持“*”符号,但是在做统计查询的时候支持count(*)。

  对于实体对象的查询,分为使用List查询和使用Iterator迭代器查询,如下使用List查询:

List students=session.createQuery("from Student").list();

   此时会出现一条查询语句,使用Iterator迭代器查询时:

Iterator iter=session.createQuery("from Student").iterate();

   会出现N+1条查询语句,其中第一条是查询id列表的sql语句,N条是根据id发出N条sql语句加载相关对象。两者的区别在于默认情况下list每次都会发出sql语句,将数据放到缓存中,而不利用缓存。iterate默认情况下会利用缓存,如果缓存中不存在就会将数据转换到内存中,然后会发出一条sql的查询语句,在每次迭代的时候仍然会产生sql语句,就出现了N+1的问题。

我们采用List和Iterator同时使用来避免N+1的问题,来优化我们的程序,提高运行效率。

List students=session.createQuery("from Student").list();
for(Iterator iter=students.iterator();iter.hasNext();){
Student student=(Student)iter.next();
System.out.println(student.getName());
}
System.out.println("-----------------------------------");

Iterator iter=session.createQuery("from Student").iterate();
while(iter.hasNext()){
Student student=(Student)iter.next();
System.out.println(student.getName());
}

   执行List操作后会把数据放到session缓存中(一级缓存),所以采用iterater首先会发出一条查询id列表的语句,再根据id到缓存中加载相关的数据,如果缓存中存在与之匹配的数据,则不再发出根据id查询的sql语句,直接使用缓存中的数据,就不会在出现N+1的问题了。

  三、条件查询:

   条件查询可以采用拼字符串的方式传递参数,也可以采用 ?来传递参数(索引从0开始),同样也可以采用参数名来传递参数。如果传递多个参数,可以采用setParamterList方法,在hql中可以使用数据库的函数,如:date_format函数。

  1、拼字符串方式:

List students=session.createQuery("select s.id, s.name from Student s where s.name like '%0%'").list();

  2、采用?来传递参数:

List students=session.createQuery("select s.id, s.name from Student s where s.name like ?")
.setParameter(0, "%0%").list();
<span style="background-color: rgb(255, 255, 255);">   </span><span style="font-family: KaiTi_GB2312;font-size:18px; background-color: rgb(255, 255, 255);">3、采用参数名来传递参数:</span>
List students=session.createQuery("select s.id, s.name from Student s where s.name like :myname")
.setParameter("myname", "%0%").list();

  4、使用数据库函数:

SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
//查询2009-08-01到2009-08-20的学生,可以调用Mysql的日期格式化函数
List students=session.createQuery("select s.id, s.name from Student s where s.createTime between ? and ?")
.setParameter(0,sdf.parse("2009-08-01 00:00:00"))
.setParameter(1,sdf.parse("2009-08-20 23:59:59"))
.list();

 四、分页查询:

分页查询主要就是两个属性的使用,

List students=session.createQuery("from Student")
.setFirstResult(1)
.setMaxResults(2)
.list();

   setFIrstResult(1)表示从1开始,setMaxResults(2)表示每页显示2条信息。

 五、对象导航查询:

    如果我们在一个类中要查询另一个类的属性,我们习惯上会创建另一个的对象,然后调用属性,采用对象导航查询,我们可以在这个类中使用对象的关联属性链接到另一个对象中取得对象的数据。

List students=session.createQuery("from Student s where s.classes.name like '%2%'")
.list();
for(Iterator iter=students.iterator();iter.hasNext();){
Student student=(Student)iter.next();
System.out.println(student.getName());
}

 六、连接查询:

  1、内连接:

List students=session.createQuery("select c.name,s.name from Student s join s.classes c")
.list();//内连接
  2、左连接:
List students=session.createQuery("select c.name,s.name from Student s left join s.classes c")
.list();//左连接  3、右连接:
List students=session.createQuery("select c.name,s.name from Student s right join s.classes c")
.list();//右连接
 七、外置命名查询:

在映射文件中使用<query>标签来定义hql,在程序中使用session.getNamedQuery()方法得到hql查询串。

Student的映射文件中引入<query>标签,

<query name="queryStudent">
<![CDATA[
select s from Student s where s.id<?
]]>
</query>

   在程序中使用session.getNamedQuery()方法:

List students=session.getNamedQuery("queryStudent")
.setParameter(0,10)
.list();

   外置的命名查询将查询语句放到了映射文件中,作为一种公共的查询字符串存在,在程序文件中都可以查询使用该字符串,这样其它的程序文件就都可以获取使用了,另外作为公共的字符串增加了修改的便利性。

 八、查询过滤器:

首先在映射文件中定义过滤器参数,然后在类的映射中使用过滤器参数。

<hibernate-mapping>
<class name="com.bjpowernode.hibernate.Student" table="t_student">
<id name="id">
<generator class="native"/>
</id>
<property name="name"/>
<property name="createTime"/>
<many-to-one name="classes" column="classesid"/>
<filter name="testFilter" condition="id < :myid"></filter>
</class>
<query name="queryStudent"> <![CDATA[ select s from Student s where s.id<? ]]> </query>

<!-- 过滤器查询需要先定义一个过滤器 -->
<filter-def name="testFilter">
<filter-param name="myid" type="integer"/>
</filter-def>
</hibernate-mapping>
       在程序中必须显示的启用过滤器,并且为过滤器赋值:

//启用过滤器
session.enableFilter("testFilter")
.setParameter("myid", 10);
List students=session.createQuery("from Student").list();

      和sql语言的学习对比,两种语言的相似度在80%,无论是何种的查询,我们只要取其相似的地方,然后明白区别在哪里,使用hql将会变得更加方便。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: