Hibernate hql查询代码实例
本文研究的主要是Hibernatehql查询的相关内容,具体如下。
HQL介绍
Hibernate语言查询(HibernateQueryLanguage,HQL)它是完全面向对象的查询语句,查询功能非常强大;具备多态、关联等特性,HQL查询也是Hibernate官方推荐使用的查询方法。
下面我们通过一个案例我分析相关查询方法
Classes.java:
publicclassClasses{ /*班级ID*/ privateintid; /*班级名称*/ privateStringname; /*班级和学生的关系*/ privateSetstudents; //省略setter和getter方法 }
Student.java:
publicclassStudent{ /*学生ID*/ privateintid; /*学生姓名*/ privateStringname; /*学生和班级的关系*/ privateClassesclasses; //省略setter和getter方法 }
Classes.hbm.xml:
Student.hbm.xml:
1.查询单一属性:
/*返回结果集属性列表,元素类型和实体类中的属性类型一致*/ Liststudents=session.createQuery("selectnamefromStudent").list(); /*遍历*/ for(Iterator iter=students.iterator();iter.hasNext();){ Stringname=(String)iter.next(); System.out.println(name); }
注:查询单一属性的时候,返回的是一个集合,集合元素的类型是该属性的类型。
2.查询多个属性,返回对象数组:
/*查询多个属性,返回的是对象数组*/ List
注:查询多个属性返回的是一个类型为对象数组的集合,这个很好理解,当查询单一属性是返回的集合元素类型就是属性的类型,但是多个类型呢?那必须是对象数组来处理啊即Object[]。
3.查询多个属性,返回对象类型的集合:
/*我们给实体对象设置对应的构造函数,然后通过查询对象的方式就可以返回一个实体对象类型的集合*/ Liststudents=session.createQuery("selectnewStudent(id,name)fromStudent").list(); /*遍历*/ for(Iteratoriter=students.iterator();iter.hasNext();){ Studentstudent=(Student)iter.next(); System.out.println(student.getId()+","+student.getName()); }
注:除了我们第二种方式返回的是一个对象数组,我们还可以给实体对象设置对应的构造函数,然后通过查询对象的方式进行查询,然后返回的就是实体类型的集合。
4.使用别名进行查询:
/*可以使用别名*/ Liststudents=session.createQuery("selects.id,s.namefromStudents").list(); /*遍历*/ for(Iterator iter=students.iterator();iter.hasNext();){ Object[]obj=(Object[])iter.next(); System.out.println(obj[0]+","+obj[1]); }
5.查询实体对象:
/*返回的是实体对象类型的集合*/ Liststudents=session.createQuery("fromStudent").list(); /*遍历*/ for(Iterator iter=students.iterator();iter.hasNext();){ Studentstudent=(Student)iter.next(); System.out.println(student.getName()); }
注:查询实体可以直接使用from类名的形式。
/*使用select就必须使用别名*/ Liststudents=session.createQuery("selectsfromStudents").list(); /*遍历*/ for(Iterator iter=students.iterator();iter.hasNext();){ Studentstudent=(Student)iter.next(); System.out.println(student.getName()); }
注:如果要使用select关键字,那么就必须使用别名。另外一点千万要注意:hql不支select*的形式。
6.N+1问题:
/** *采用list查询实体对象会发出一条查询语句,取得实体对象数据 * *Hibernate:selectstudent0_.idasid0_,student0_.nameasname0_, *student0_.createTimeascreateTime0_,student0_.classesidasclassesid0_ *fromt_studentstudent0_ */ Liststudents=session.createQuery("fromStudent").list(); /*遍历*/ for(Iterator iter=students.iterator();iter.hasNext();){ Studentstudent=(Student)iter.next(); System.out.println(student.getName()); }
注:使用.list()的方式进行对象查询,只会发出一条语句,即取得实体对象数据的语句。
/** *会出现N+1问题,所谓的N+1指的是发出了N+1条sql语句 * *1:发出一条查询id列表的语句 *Hibernate:selectstudent0_.idascol_0_0_fromt_studentstudent0_ * *N:根据id发出N条sql语句,加载相关的对象 *Hibernate:selectstudent0_.idasid0_0_,student0_.nameasname0_0_, *student0_.createTimeascreateTime0_0_,student0_.classesidasclassesid0_0_ *fromt_studentstudent0_wherestudent0_.id=? * */ Iteratoriter=session.createQuery("fromStudent").iterate(); /*遍历*/ while(iter.hasNext()){ Studentstudent=(Student)iter.next(); System.out.println(student.getName()); }
注:通过iterator()方式进行对象查询,会发出N+1条语句,首先会发出一条语句查询出实体对象的ID,然后在根据各自的ID发出N条语句去查询N个对象,这中形式性能是比较差的。
/*通过List查询把查询出的集合存放在一级缓存即session级缓存中*/ Liststudents=session.createQuery("fromStudent").list(); /*遍历*/ for(Iterator iter=students.iterator();iter.hasNext();){ Studentstudent=(Student)iter.next(); System.out.println(student.getName()); } System.out.println("-----------------------------------------------------"); /** *避免了N+1问题 * *因为执行list操作后会将数据放到session的缓存中(一级缓存),所以采用iterate的时候 *首先会发出一条查询id列表的语句,再根据id到缓存中加载相应的数据,如果缓存中存在与之匹配的数据 *则不再发出根据id查询的sql语句,直接使用缓存中的数据 * *Iterate方法如果缓存中存在数据,它可以提高性能,否则出现N+1问题 * */ Iterator iter=session.createQuery("fromStudent").iterate(); /*遍历*/ while(iter.hasNext()){ Studentstudent=(Student)iter.next(); System.out.println(student.getName()); }
注:其实Hibernate提供iterator()的方式查询是为了提高性能的,那为什么反而帮了倒忙呢?原因是iterator()是从一级缓存中取数据的,如果缓存中有数据,那么它的效率毫无疑问会相当的给力,但是当我第一次查询的时候缓存中怎么可能会有数据呢,所以就导致了所谓的N+1问题。上面这段代码可以避免N+1问题,它的思路是先用list()进行查询,因为list()查询出来以后,在一级缓存汇总就存在了数据,使用iterator()的时候,效率就会非常的高。
7.条件查询:
/*根据条件进行查询(这里通常都使用别名,比较方便)*/ Liststudents=session.createQuery("selects.id,s.namefromStudentswheres.namelike'%0%'").list(); /*遍历*/ for(Iterator iter=students.iterator();iter.hasNext();){ Object[]obj=(Object[])iter.next(); System.out.println(obj[0]+","+obj[1]); }
注:条件查询和原生的sql相同,都是where关键字。另外通常使用别名比较方便,上述程序是查询多个属性,所以返回的是对象数组类型的集合,对象数组中的元素就是对应的属性。
8.占位符的形式查询:
/*链式编程*/ Liststudents=session.createQuery("selects.id,s.namefromStudentswheres.namelike?") .setParameter(0,"%0%") .list(); /*遍历*/ for(Iterator iter=students.iterator();iter.hasNext();){ Object[]obj=(Object[])iter.next(); System.out.println(obj[0]+","+obj[1]); }
注:可以通过占位符的形式进行传参,这种方式可以防止SQL注入。
9.自定义参数的形式:
/*链式编程*/ Liststudents=session.createQuery("selects.id,s.namefromStudentswheres.namelike:myname") .setParameter("myname","%0%") .list(); /*对象数组*/ for(Iterator iter=students.iterator();iter.hasNext();){ Object[]obj=(Object[])iter.next(); System.out.println(obj[0]+","+obj[1]); }
注:like:myname冒号后面是没有空格的,否则会出错。
10.查询条件为in的形式:
[java]viewplaincopy /*采用in的方式,形参只要一个即可*/ Liststudents=session.createQuery("selects.id,s.namefromStudentswheres.idin(:ids)") .setParameterList("ids",newObject[]{1,2,3,4,5}) .list(); /*遍历*/ for(Iterator iter=students.iterator();iter.hasNext();){ Object[]obj=(Object[])iter.next(); System.out.println(obj[0]+","+obj[1]); }
注:in后面的括号中只要有一个形参即可,我们设置参数值的时候,可以通过对象数组就行传值。
11.使用数据库个性化函数:
/*查询2009-08的学生,可以调用mysql的日期格式化函数*/ Liststudents=session.createQuery("selects.id,s.namefromStudentswheredate_format(s.createTime,'%Y-%m')=?") .setParameter(0,"2009-08") .list(); /*遍历*/ for(Iterator iter=students.iterator();iter.hasNext();){ Object[]obj=(Object[])iter.next(); System.out.println(obj[0]+","+obj[1]); }
SimpleDateFormatsdf=newSimpleDateFormat("yyyy-MM-ddHH:mm:ss"); /*查询2009-08-01到2009-08-20的学生,可以调用mysql的日期格式化函数*/ Liststudents=session.createQuery("selects.id,s.namefromStudentswheres.createTimebetween?and?") .setParameter(0,sdf.parse("2009-08-0100:00:00")) .setParameter(1,sdf.parse("2009-08-2023:59:59")) .list(); /*遍历*/ for(Iterator iter=students.iterator();iter.hasNext();){ Object[]obj=(Object[])iter.next(); System.out.println(obj[0]+","+obj[1]); }
12.使用原生态的SQL语句:
/*使用select*必须使用原生态的SQL语句,另外它类似于hql查询多个属性,所以返回的是一个对象数组类型的集合*/ Liststudents=session.createSQLQuery("select*fromt_student").list(); /*遍历*/ for(Iterator iter=students.iterator();iter.hasNext();){ Object[]obj=(Object[])iter.next(); System.out.println(obj[0]+","+obj[1]); }
注:hql不支持select*的查询形式,但是Hibernate支持原生态的SQL语句,我们可以利用SQL语句进行查询,另外它类似于HQL的查询多个属性,所以返回的是一个对象数组类型的集合。
13.分页查询
/*分页查询,setFirstResult(1)表示从第一条数据开始查询;setMaxResult(2)表示每页显示2条数据*/ Liststudents=session.createQuery("fromStudent") .setFirstResult(1) .setMaxResults(2) .list(); /*遍历*/ for(Iteratoriter=students.iterator();iter.hasNext();){ Studentstudent=(Student)iter.next(); System.out.println(student.getName()); }
14.导航查询
/*导航查询,s.classes.name从学生导航到班级在导航到班级名称(这是从多的一端导航到少的一端,反过来也可以)*/ Liststudents=session.createQuery("fromStudentswheres.classes.namelike'%2%'") .list(); /*遍历*/ for(Iterator iter=students.iterator();iter.hasNext();){ Studentstudent=(Student)iter.next(); System.out.println(student.getName()); }
注:上述查询语句中的s.classes.name是从学生导航到班级classes在获取班级的名称name。也可以反过来导航:从班级导航到学生在得到某个属性。另外程序中查询语句的意思是要查询班级名称中含有2的所有学生。
15.内连接查询
/*内连接,使用join关键字即可*/ Liststudents=session.createQuery("selectc.name,s.namefromStudentsjoins.classesc") .list(); /*遍历*/ for(Iterator iter=students.iterator();iter.hasNext();){ Object[]obj=(Object[])iter.next(); System.out.println(obj[0]+","+obj[1]); }
注:内连接关键字为join,另外还是用了别名和导航进行连接。上述查询语句的意思为:从学生表和班级表中查询中班级名称和学生名称(内连接是查询出必须有值得属性,比如没有班级没有学生或者学生没有班级是查询不出来的)。
16.左连接
/*左连接使用关键字leftjoin*/ Liststudents=session.createQuery("selectc.name,s.namefromStudentsleftjoins.classesc") .list(); /*遍历*/ for(Iterator iter=students.iterator();iter.hasNext();){ Object[]obj=(Object[])iter.next(); System.out.println(obj[0]+","+obj[1]); }
注:使用左连接的关键字为leftjoin。上述查询语句的意思为:从学生和班级表中,查询出班级名称和学生名称,因为是左连接,所以没有班级的学生也会被查询出来。
17.右连接
[java]viewplaincopy /*右连接关键字为rightjoin*/ Liststudents=session.createQuery("selectc.name,s.namefromStudentsrightjoins.classesc") .list(); /*遍历*/ for(Iterator iter=students.iterator();iter.hasNext();){ Object[]obj=(Object[])iter.next(); System.out.println(obj[0]+","+obj[1]); }
注:使用右连接的关键字为rightjoin。上述查询语句的意思为:从学生和班级表中,查询出班级名称和学生名称,因为是右连接,所以没有学生的班级会被查询出来。
18.统计查询
Longcount=(Long)session.createQuery("selectcount(*)fromStudent").uniqueResult();
注:hql中唯有统计查询才可以带*号。uniqueResult()表示只有一条结果集,返回的是Long类型。
19.复合查询
/*查询语句*/ Stringhql="selectc.name,count(s)fromClassescjoinc.studentssgroupbyc.nameorderbyc.name"; Liststudents=session.createQuery(hql).list(); /*遍历*/ for(inti=0;i 注:hql同样支持分组、排序等等。上述语句的意思是:查询每个班级的名称并且查询出每个班级的学生人数,按班级名称分组,按班级名称排序
总结
以上就是本文关于Hibernatehql查询代码实例的全部内容,希望对大家有所帮助。感兴趣的朋友可以继续参阅本站其他相关专题,如有不足之处,欢迎留言指出。感谢朋友们对本站的支持!