hql基本介紹
HQL(HibernateQuery Language)查詢提供了豐富的和靈活的查詢特性,在涵蓋Criteria查詢的所有功能的前提下,提供了類似標準SQL語句的查詢方式,同時也提供了更加面向對象的封裝。因此Hibernate將HQL查詢方式立爲官方推薦的標準查詢方式,完整的HQL語句形式如下: Select/update/delete…… from …… where …… group by ……having …… order by …… asc/desc 其中的update/delete爲Hibernate3中所新添加的功能,可見HQL查詢非常類似於標準SQL查詢。由於HQL查詢在整個Hibernate實體操作體系中的核心地位,這一節我將專門圍繞HQL操作的具體技術細節進行講解。
在hql中關鍵字不區分大小寫,通常小寫,類的名稱和屬性名稱必須區分大小寫
HQL包括的各種查詢
1、簡單屬性查詢【重要】
*單一屬性查詢,返會屬性結果集列表,元素類型和實體類中相應的類型一致
*多個屬性查詢,多個屬性查詢返會對象數組,對象數組的長度取決於屬性的個數,對象數組中元素的類型取決於屬性在實體類中的類型
*如果認爲返會數組不夠對象化,可以使用hql動態實例化Student對象
單一屬性查詢
//返回結果集屬性列表,元素類型和實體類中的屬性類型一致
Liststudents = session.createQuery("select name from Student").list();
for(Iterator iter=students.iterator(); iter.hasNext();) {
Stringname = (String)iter.next();
System.out.println(name);
}
多個屬性查詢
//查詢多個屬性,返回對象數組集合
//數組元素的類型與查詢的屬性類型一致
//數組的長度與select中查詢的屬性個數一致
Liststudents = session.createQuery("select id, name fromStudent").list();
for(Iterator iter=students.iterator(); iter.hasNext();) {
Object[]obj = (Object[])iter.next();
System.out.println(obj[0]+ ", " + obj[1]);
}
多個屬性查詢,返回Student
//可以使用hql返回Student對象
//需要提供構造函數
Liststudents = session.createQuery("select new Student(id, name) fromStudent").list();
for(Iterator iter=students.iterator(); iter.hasNext();) {
Studentstudent = (Student)iter.next();
System.out.println(student.getId()+ ", " + student.getName());
}
使用別名
//可以使用別名
Liststudents = session.createQuery("select s.id, s.name from Students").list();
for(Iterator iter=students.iterator(); iter.hasNext();) {
Object[]obj = (Object[])iter.next();
System.out.println(obj[0]+ ", " + obj[1]);
}
//可以採用as命名別名
Liststudents = session.createQuery("select s.id, s.name from Student ass").list();
for(Iterator iter=students.iterator(); iter.hasNext();) {
Object[]obj = (Object[])iter.next();
System.out.println(obj[0]+ ", " + obj[1]);
}
2、實體對象查詢【重要】
* N + 1問題,就是發出了N+1條sql語句
1:首先發出查詢對象id列表的語句
N:根據id到緩存中查詢,如果緩存中不存在與之匹配的數據,那麼會根據id發出相應的sql語句
*list和iterate的區別?
list:默認情況下list每次都會發出sql語句,list會將數據放到緩存中,而不利用緩存
iterate:默認情況下iterate利用緩存,如果緩存中不存在會出現N+1問題
//返回Student對象的集合
//可以忽select關鍵字
Liststudents = session.createQuery("from Student").list();
for(Iterator iter=students.iterator(); iter.hasNext();) {
Studentstudent = (Student)iter.next();
System.out.println(student.getName());
}
/**
* 採用list查詢實體對象會發出一條查詢語句,取得實體對象數據
*
* Hibernate: select student0_.id as id0_,student0_.name as name0_,
* student0_.createTime as createTime0_,student0_.classesid as classesid0_
* from t_student student0_
*/
Liststudents = session.createQuery("from Student").list();
for(Iterator iter=students.iterator(); iter.hasNext();) {
Studentstudent = (Student)iter.next();
System.out.println(student.getName());
}
3、條件查詢【重要】
*可以採用拼字符串的方式傳遞參數
//可以拼串
Liststudents = session.createQuery("select s.id, s.name from Student s wheres.name like '%0%'").list();
for(Iterator iter=students.iterator(); iter.hasNext();) {
Object[]obj = (Object[])iter.next();
System.out.println(obj[0]+ ", " + obj[1]);
}
* 可以採用?來傳遞參數(索引從0開始)
//可以使用?方式傳遞參數
//索引從0開始,不同於jdbc從1開始
//值能使用單引號引起來
//Liststudents = session.createQuery("select s.id, s.name from Student s wheres.name like ?").list();
// Queryquery = session.createQuery("selects.id, s.name from Student s where s.name like ?");
// query.setParameter(0,"%0%");
// Liststudents = query.list();
//方法鏈編程,建議採用此種方式
Liststudents = session.createQuery("select s.id, s.name from Student s wheres.name like ?")
.setParameter(0,"%0%")
.list();
for(Iterator iter=students.iterator(); iter.hasNext();) {
Object[]obj = (Object[])iter.next();
System.out.println(obj[0]+ ", " + obj[1]);
}
* 可以採用:參數名 來傳遞參數
//可以採用:參數名 的方式傳遞參數
Liststudents = session.createQuery("select s.id, s.name from Student s wheres.name like :myname")
.setParameter("myname", "%0%")
.list();
for(Iterator iter=students.iterator(); iter.hasNext();) {
Object[]obj = (Object[])iter.next();
System.out.println(obj[0]+ ", " + obj[1]);
}
*如果傳遞多個參數,可以採用setParamterList方法
//採用?方式,查詢學號爲1,2,3,4,5的學生
Liststudents = session.createQuery("select s.id, s.name from Student s wheres.id in(?, ?, ?, ?, ?)")
.setParameter(0,1)
.setParameter(1,2)
.setParameter(2,3)
.setParameter(3,4)
.setParameter(4,5)
.list();
for(Iterator iter=students.iterator(); iter.hasNext();) {
Object[]obj = (Object[])iter.next();
System.out.println(obj[0]+ ", " + obj[1]);
}
*在hql中可以使用數據庫的函數,如:date_format
//採用:參數名 方式,查詢學號爲1,2,3,4,5的學生
Liststudents = session.createQuery("select s.id, s.name from Student s wheres.id in(:ids)")
.setParameterList("ids",new Object[]{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]);
}
//查詢2009-08的學生,可以調用mysql的日期格式化函數
Liststudents = session.createQuery("select s.id, s.name from Student s wheredate_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 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
//查詢2009-08-01到2009-08-20的學生,可以調用mysql的日期格式化函數
Liststudents = session.createQuery("select s.id, s.name from Student s wheres.createTime between ? and ?")
.setParameter(0,sdf.parse("2009-08-01 00:00:00"))
.setParameter(1,sdf.parse("2009-08-20 23:59:59"))
.list();
for(Iterator iter=students.iterator(); iter.hasNext();) {
Object[]obj = (Object[])iter.next();
System.out.println(obj[0]+ ", " + obj[1]);
}
4、hibernate直接使用sql語句查詢
Liststudents = session.createSQLQuery("select * from t_student").list();
for(Iterator iter=students.iterator(); iter.hasNext();) {
Object[]obj = (Object[])iter.next();
System.out.println(obj[0]+ ", " + obj[1]);
}
5、外置命名查詢
* 在映射文件中使用<query>標籤來定義hql
* 在程序中使用session.getNamedQuery()方法得到hql查詢串
<queryname="queryStudent">
<![CDATA[
selects from Student s where s.id <?
]]>
</query>
List students =session.getNamedQuery("queryStudent")
.setParameter(0,10)
.list();
for (Iteratoriter=students.iterator(); iter.hasNext();) {
Studentstudent = (Student)iter.next();
System.out.println(student.getName());
}
6、查詢過濾器
*在映射文件中定義過濾器參數
*在類的映射中使用過濾器參數
*在程序中必須顯示的啓用過濾器,並且爲過濾器參數賦值
<filter-defname="testFilter">
<filter-paramtype="integer" name="myid"/>
</filter-def>
session.enableFilter("testFilter")
.setParameter("myid",10);
Liststudents = session.createQuery("from Student").list();
for(Iterator iter=students.iterator(); iter.hasNext();) {
Studentstudent = (Student)iter.next();
System.out.println(student.getName());
}
7、分頁查詢【重要】
*setFirstResult(),從0開始
*setMaxResults(),每頁顯示的記錄數
Liststudents = session.createQuery("from Student")
.setFirstResult(1)
.setMaxResults(2)
.list();
for(Iterator iter=students.iterator(); iter.hasNext();) {
Studentstudent = (Student)iter.next();
System.out.println(student.getName());
}
8、對象導航查詢【重要】
Liststudents = session.createQuery("from Student s where s.classes.name like'%2%'")
.list();
for(Iterator iter=students.iterator(); iter.hasNext();) {
Studentstudent = (Student)iter.next();
System.out.println(student.getName());
}
9、連接查詢【重要】
* 內連接
* 外連接(左連接/右連接)left join right join
Liststudents = session.createQuery("select c.name, s.name from Student s joins.classes c")
.list();
for(Iterator iter=students.iterator(); iter.hasNext();) {
Object[]obj = (Object[])iter.next();
System.out.println(obj[0]+ ", " + obj[1]);
}
10、統計查詢【重要】
Longcount = (Long)session.createQuery("select count(*) fromStudent").uniqueResult();
11、DML風格的操作(儘量少用,因爲和緩存不同步)
@SuppressWarnings("unused")
//Studentstudent = (Student)session.load(Student.class, 1);
Studentstudent = (Student)session.get(Student.class, 1);
//數據庫表中更新了,但緩存不更新
//所以一般不建議使用,除非有必須,如遇到性能問題
session.createQuery("updateStudent s set s.name=? where s.id<?")
.setParameter(0,"王五")
.setParameter(1,5)
.executeUpdate();
//student= (Student)session.load(Student.class, 1);
student= (Student)session.get(Student.class, 1);
System.out.println("student.name="+ student.getName());
總結:
HQL查詢跟我們之前學過的SQL有百分之八十的相似,所以,學起來不僅沒有抵觸反而更增加了學習的興趣,從而更好的去學習HQL,並且對SQL也有一定的惠顧,這也就是我們所學的N+1理論,同時我們從HQL的發展也可以看出,他並沒有獨闢蹊徑,重新編寫一種語言,而是更多地沿用SQL的使用習慣,讓使用的人更加方便,也其實也是我們編寫軟件的宗旨,並不是越奇特越好,而是能讓用戶能夠由衷的感覺到他不生澀,即達到了用戶的使用目的,也讓用戶能夠由衷的喜歡你的軟件