您好,登錄后才能下訂單哦!
本文研究的主要是Hibernate hql查詢的相關(guān)內(nèi)容,具體如下。
Hibernate語言查詢(Hibernate Query Language,HQL)它是完全面向?qū)ο蟮牟樵冋Z句,查詢功能非常強大;具備多態(tài)、關(guān)聯(lián)等特性,HQL查詢也是Hibernate官方推薦使用的查詢方法。
下面我們通過一個案例我分析相關(guān)查詢方法
Classes.java:
public class Classes { /*班級ID*/ private int id; /*班級名稱*/ private String name; /*班級和學生的關(guān)系*/ private Set<Student> students; //省略setter和getter方法 }
Student.java:
public class Student { /*學生ID*/ private int id; /*學生姓名*/ private String name; /*學生和班級的關(guān)系*/ private Classes classes; //省略setter和getter方法 }
Classes.hbm.xml:
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="com.lixue.bean"> <!-- 設置lazy為false --> <class name="Classes" table="t_classes" lazy="false"> <id name="id"> <generator class="native"/> </id> <property name="name"/> <!-- 一對多映射 ,inverse="true"表示交給對端維護關(guān)系--> <set name="students" inverse="true"> <key column="classesid"/> <one-to-many class="Student"/> </set> </class> </hibernate-mapping>
Student.hbm.xml:
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="com.lixue.bean"> <class name="Student" table="t_student"> <id name="id"> <generator class="native"/> </id> <!-- 映射普通屬性 --> <property name="name"/> <!-- 多對一 映射,在多的一端加上外鍵--> <many-to-one name="classes" column="classesid"/> </class> </hibernate-mapping>
/*返回結(jié)果集屬性列表,元素類型和實體類中的屬性類型一致*/ List<String> students = session.createQuery("select name from Student").list(); /*遍歷*/ for (Iterator<String> iter=students.iterator(); iter.hasNext();) { String name = (String)iter.next(); System.out.println(name); }
注:查詢單一屬性的時候,返回的是一個集合,集合元素的類型是該屬性的類型。
/*查詢多個屬性,返回的是對象數(shù)組*/ List<Object[]> students = session.createQuery("select id, name from Student").list(); /*遍歷*/ for (Iterator<Object[]> iter=students.iterator(); iter.hasNext();) { Object[] obj = (Object[])iter.next(); System.out.println(obj[0] + ", " + obj[1]); }
注:查詢多個屬性返回的是一個類型為對象數(shù)組的集合,這個很好理解,當查詢單一屬性是返回的集合元素類型就是屬性的類型,但是多個類型呢?那必須是對象數(shù)組來處理啊即Object[]。
/*我們給實體對象設置對應的構(gòu)造函數(shù),然后通過查詢對象的方式就可以返回一個實體對象類型的集合*/ List students = session.createQuery("select new Student(id, name) from Student").list(); /*遍歷*/ for (Iterator iter=students.iterator(); iter.hasNext();) { Student student = (Student)iter.next(); System.out.println(student.getId() + ", " + student.getName()); }
注:除了我們第二種方式返回的是一個對象數(shù)組,我們還可以給實體對象設置對應的構(gòu)造函數(shù),然后通過查詢對象的方式進行查詢,然后返回的就是實體類型的集合。
/*可以使用別名*/ List<Object[]> students = session.createQuery("select s.id, s.name from Student s").list(); /*遍歷*/ for (Iterator<Object[]> iter=students.iterator(); iter.hasNext();) { Object[] obj = (Object[])iter.next(); System.out.println(obj[0] + ", " + obj[1]); }
/*返回的是實體對象類型的集合*/ List<Student> students = session.createQuery("from Student").list(); /*遍歷*/ for (Iterator<Student> iter=students.iterator(); iter.hasNext();) { Student student = (Student)iter.next(); System.out.println(student.getName()); }
注:查詢實體可以直接使用from 類名的形式。
/*使用select就必須使用別名*/ List<Student> students = session.createQuery("select s from Student s").list(); /*遍歷*/ for (Iterator<Student> iter=students.iterator(); iter.hasNext();) { Student student = (Student)iter.next(); System.out.println(student.getName()); }
注:如果要使用select關(guān)鍵字,那么就必須使用別名。另外一點千萬要注意:hql不支select * 的形式。
/** * 采用list查詢實體對象會發(fā)出一條查詢語句,取得實體對象數(shù)據(jù) * * Hibernate: select student0_.id as id0_, student0_.name as name0_, * student0_.createTime as createTime0_, student0_.classesid as classesid0_ * from t_student student0_ */ List<Student> students = session.createQuery("from Student").list(); /*遍歷*/ for (Iterator<Student> iter=students.iterator(); iter.hasNext();) { Student student = (Student)iter.next(); System.out.println(student.getName()); }
注:使用.list()的方式進行對象查詢,只會發(fā)出一條語句,即取得實體對象數(shù)據(jù)的語句。
/** * 會出現(xiàn)N+1問題,所謂的N+1指的是發(fā)出了N+1條sql語句 * * 1:發(fā)出一條查詢id列表的語句 * Hibernate: select student0_.id as col_0_0_ from t_student student0_ * * N:根據(jù)id發(fā)出N條sql語句,加載相關(guān)的對象 * Hibernate: select student0_.id as id0_0_, student0_.name as name0_0_, * student0_.createTime as createTime0_0_, student0_.classesid as classesid0_0_ * from t_student student0_ where student0_.id=? * */ Iterator<Student> iter = session.createQuery("from Student").iterate(); /*遍歷*/ while (iter.hasNext()) { Student student = (Student)iter.next(); System.out.println(student.getName()); }
注:通過iterator()方式進行對象查詢,會發(fā)出N+1條語句,首先會發(fā)出一條語句查詢出實體對象的ID,然后在根據(jù)各自的ID發(fā)出N條語句去查詢N個對象,這中形式性能是比較差的。
/*通過List查詢把查詢出的集合存放在一級緩存即session級緩存中*/ List<Student> students = session.createQuery("from Student").list(); /*遍歷*/ for (Iterator<Student> iter=students.iterator(); iter.hasNext();) { Student student = (Student)iter.next(); System.out.println(student.getName()); } System.out.println("-----------------------------------------------------"); /** * 避免了N+1問題 * * 因為執(zhí)行l(wèi)ist操作后會將數(shù)據(jù)放到session的緩存中(一級緩存),所以采用iterate的時候 * 首先會發(fā)出一條查詢id列表的語句,再根據(jù)id到緩存中加載相應的數(shù)據(jù),如果緩存中存在與之匹配的數(shù)據(jù) * 則不再發(fā)出根據(jù)id查詢的sql語句,直接使用緩存中的數(shù)據(jù) * * Iterate方法如果緩存中存在數(shù)據(jù),它可以提高性能,否則出現(xiàn)N+1問題 * */ Iterator<Student> iter = session.createQuery("from Student").iterate(); /*遍歷*/ while (iter.hasNext()) { Student student = (Student)iter.next(); System.out.println(student.getName()); }
注:其實Hibernate提供iterator()的方式查詢是為了提高性能的,那為什么反而幫了倒忙呢?原因是iterator()是從一級緩存中取數(shù)據(jù)的,如果緩存中有數(shù)據(jù),那么它的效率毫無疑問會相當?shù)慕o力,但是當我第一次查詢的時候緩存中怎么可能會有數(shù)據(jù)呢,所以就導致了所謂的N+1問題。上面這段代碼可以避免N+1問題,它的思路是先用list()進行查詢,因為list()查詢出來以后,在一級緩存匯總就存在了數(shù)據(jù),使用iterator()的時候,效率就會非常的高。
/*根據(jù)條件進行查詢(這里通常都使用別名,比較方便 )*/ List<Object[]> students = session.createQuery("select s.id, s.name from Student s where s.name like '%0%'").list(); /*遍歷*/ for (Iterator<Object[]> iter=students.iterator(); iter.hasNext();) { Object[] obj = (Object[])iter.next(); System.out.println(obj[0] + ", " + obj[1]); }
注:條件查詢和原生的sql相同,都是where關(guān)鍵字。另外通常使用別名比較方便,上述程序是查詢多個屬性,所以返回的是對象數(shù)組類型的集合,對象數(shù)組中的元素就是對應的屬性。
/*鏈式編程*/ List<Object[]> students = session.createQuery("select s.id, s.name from Student s where s.name like ?") .setParameter(0, "%0%") .list(); /*遍歷*/ for (Iterator<Object[]> iter=students.iterator(); iter.hasNext();) { Object[] obj = (Object[])iter.next(); System.out.println(obj[0] + ", " + obj[1]); }
注:可以通過占位符的形式進行傳參,這種方式可以防止SQL注入。
/*鏈式編程*/ List<Object[]> students = session.createQuery("select s.id, s.name from Student s where s.name like :myname") .setParameter("myname", "%0%") .list(); /*對象數(shù)組*/ for (Iterator<Object[]> iter=students.iterator(); iter.hasNext();) { Object[] obj = (Object[])iter.next(); System.out.println(obj[0] + ", " + obj[1]); }
注:like :myname冒號后面是沒有空格的,否則會出錯。
[java] view plain copy /*采用in的方式,形參只要一個即可*/ List<Object[]> students = session.createQuery("select s.id, s.name from Student s where s.id in(:ids)") .setParameterList("ids", new Object[]{1, 2, 3, 4, 5}) .list(); /*遍歷*/ for (Iterator<Object[]> iter=students.iterator(); iter.hasNext();) { Object[] obj = (Object[])iter.next(); System.out.println(obj[0] + ", " + obj[1]); }
注:in后面的括號中只要有一個形參即可,我們設置參數(shù)值的時候,可以通過對象數(shù)組就行傳值。
/*查詢2009-08的學生,可以調(diào)用mysql的日期格式化函數(shù)*/ List<Object[]> students = session.createQuery("select s.id, s.name from Student s where date_format(s.createTime, '%Y-%m')=?") .setParameter(0, "2009-08") .list(); /*遍歷*/ for (Iterator<Object[]> iter=students.iterator(); iter.hasNext();) { Object[] obj = (Object[])iter.next(); System.out.println(obj[0] + ", " + obj[1]); }
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); /*查詢2009-08-01 到2009-08-20的學生,可以調(diào)用mysql的日期格式化函數(shù)*/ List<Object[]> 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(); /*遍歷*/ for (Iterator<Object[]> iter=students.iterator(); iter.hasNext();) { Object[] obj = (Object[])iter.next(); System.out.println(obj[0] + ", " + obj[1]); }
/*使用select * 必須使用原生態(tài)的SQL語句,另外它類似于hql查詢多個屬性,所以返回的是一個對象數(shù)組類型的集合*/ List<Object[]> students = session.createSQLQuery("select * from t_student").list(); /*遍歷*/ for (Iterator<Object[]> iter = students.iterator(); iter.hasNext();) { Object[] obj = (Object[]) iter.next(); System.out.println(obj[0] + ", " + obj[1]); }
注:hql不支持select * 的查詢形式,但是Hibernate支持原生態(tài)的SQL語句,我們可以利用SQL語句進行查詢,另外它類似于HQL的查詢多個屬性,所以返回的是一個對象數(shù)組類型的集合。
/*分頁查詢,setFirstResult(1)表示從第一條數(shù)據(jù)開始查詢;setMaxResult(2)表示每頁顯示2條數(shù)據(jù)*/ List students = session.createQuery("from Student") .setFirstResult(1) .setMaxResults(2) .list(); /*遍歷*/ for (Iterator iter=students.iterator(); iter.hasNext();) { Student student = (Student)iter.next(); System.out.println(student.getName()); }
/*導航查詢,s.classes.name從學生導航到班級在導航到班級名稱(這是從多的一端導航到少的一端,反過來也可以)*/ List<Student> students = session.createQuery("from Student s where s.classes.name like '%2%'") .list(); /*遍歷*/ for (Iterator<Student> iter=students.iterator(); iter.hasNext();) { Student student = (Student)iter.next(); System.out.println(student.getName()); }
注:上述查詢語句中的s.classes.name是從學生導航到班級classes在獲取班級的名稱name。也可以反過來導航:從班級導航到學生在得到某個屬性。另外程序中查詢語句的意思是要查詢班級名稱中含有2的所有學生。
/*內(nèi)連接,使用join關(guān)鍵字即可*/ List<Object[]> students = session.createQuery("select c.name, s.name from Student s join s.classes c") .list(); /*遍歷*/ for (Iterator<Object[]> iter=students.iterator(); iter.hasNext();) { Object[] obj = (Object[])iter.next(); System.out.println(obj[0] + ", " + obj[1]); }
注:內(nèi)連接關(guān)鍵字為join,另外還是用了別名和導航進行連接。上述查詢語句的意思為:從學生表和班級表中查詢中班級名稱和學生名稱(內(nèi)連接是查詢出必須有值得屬性,比如沒有班級沒有學生或者學生沒有班級是查詢不出來的)。
/*左連接使用關(guān)鍵字left join*/ List<Object[]> students = session.createQuery("select c.name, s.name from Student s left join s.classes c") .list(); /*遍歷*/ for (Iterator<Object[]> iter=students.iterator(); iter.hasNext();) { Object[] obj = (Object[])iter.next(); System.out.println(obj[0] + ", " + obj[1]); }
注:使用左連接的關(guān)鍵字為left join。上述查詢語句的意思為:從學生和班級表中,查詢出班級名稱和學生名稱,因為是左連接,所以沒有班級的學生也會被查詢出來。
[java] view plain copy /*右連接關(guān)鍵字為right join*/ List<Object[]> students = session.createQuery("select c.name, s.name from Student s right join s.classes c") .list(); /*遍歷*/ for (Iterator<Object[]> iter=students.iterator(); iter.hasNext();) { Object[] obj = (Object[])iter.next(); System.out.println(obj[0] + ", " + obj[1]); }
注:使用右連接的關(guān)鍵字為right join。上述查詢語句的意思為:從學生和班級表中,查詢出班級名稱和學生名稱,因為是右連接,所以沒有學生的班級會被查詢出來。
Long count = (Long)session.createQuery("select count(*) from Student").uniqueResult();
注:hql中唯有統(tǒng)計查詢才可以帶*號。uniqueResult()表示只有一條結(jié)果集,返回的是Long類型。
/*查詢語句*/ String hql = "select c.name, count(s) from Classes c join c.students s group by c.name order by c.name"; List<Object[]> students = session.createQuery(hql).list(); /*遍歷*/ for (int i=0; i<students.size(); i++) { Object[] obj = (Object[])students.get(i); System.out.println(obj[0] + ", " + obj[1]); }
注:hql同樣支持分組、排序等等。上述語句的意思是:查詢每個班級的名稱并且查詢出每個班級的學生人數(shù),按班級名稱分組,按班級名稱排序
以上就是本文關(guān)于Hibernate hql查詢代碼實例的全部內(nèi)容,希望對大家有所幫助。感興趣的朋友可以繼續(xù)參閱本站其他相關(guān)專題,如有不足之處,歡迎留言指出。感謝朋友們對本站的支持!
免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。