Hibernate 配備了一種非常強大的查詢語言,這種語言看上去很像 SQL。但是不要被語法結構上的相似所迷惑,HQL 是非常有意識的被設計為完全物件導向的查詢,它可以理解如繼承、多型和關聯之類的概念。
基本規則
- HQL語法類似於SQL,也是一種select from結構的語句。但是他後面跟的不是表名和欄位名,而是類名和屬性名。
- HQL基本查詢語法跟SQL很類似
- HQL大小寫不敏感。但是,設計java類名、包名、屬性名時大小寫敏感。
- 包名的使用情況。比如:如果註冊的實體類Emp只有一個類,那麼查詢時可以不加包名,hibernate會自動檢索到Emp類。但是如果註冊多個實體類,名字都叫Emp。此時就要增加包名來區別多個實體類。
第一個HQL查詢
1 1 package com.qcf.test; 2 2 3 3 import java.util.List; 4 4 5 5 6 6 import org.hibernate.Query; 7 7 import org.hibernate.Session; 8 8 import org.hibernate.SessionFactory; 9 9 import org.hibernate.Transaction; 10 10 import org.hibernate.cfg.Configuration; 11 11 12 12 import com.qcf.po.User; 13 13 14 14 public class TestHiber { 15 15 public static void main(String[] args) { 16 16 //讀取配置檔案中的資訊 17 17 Configuration con=new Configuration().configure(); 18 18 //獲取sessionFactory物件 19 19 SessionFactory factory=con.buildSessionFactory(); 20 20 //獲取Session物件 21 21 Session session=factory.openSession(); 22 22 String hql="from User"; 23 23 //建立HQL查詢 24 24 Query query= session.createQuery(hql); 25 25 List list=query.list(); 26 26 //對查詢的結果進行遍歷 27 27 for (int i = 0; i < list.size(); i++) { 28 28 User user=(User) list.get(i); 29 29 System.out.println(user.getName()); 30 30 } 31 31 32 32 session.close(); 33 33 } 34 34 }
查詢結果:
根據返回型別劃分HQL查詢
1、單個物件
在這裡提醒一下,這個hql意識統計資料庫的記錄數,一般我們都知道count(1) 要比count(*) 快多了,但是這裡必須使用count(*) 使用count(1)就會報錯!
1 1 package com.qcf.test; 2 2 3 3 import java.util.List; 4 4 5 5 6 6 import org.hibernate.Query; 7 7 import org.hibernate.Session; 8 8 import org.hibernate.SessionFactory; 9 9 import org.hibernate.Transaction; 10 10 import org.hibernate.cfg.Configuration; 11 11 12 12 import com.qcf.po.User; 13 13 14 14 public class TestHiber { 15 15 public static void main(String[] args) { 16 16 //讀取配置檔案中的資訊 17 17 Configuration con=new Configuration().configure(); 18 18 //獲取sessionFactory物件 19 19 SessionFactory factory=con.buildSessionFactory(); 20 20 //獲取Session物件 21 21 Session session=factory.openSession(); 22 22 String hql="select count(*) from User"; 23 23 //建立HQL查詢 24 24 Query query= session.createQuery(hql); 25 25 Number n=(Number) query.uniqueResult(); 26 26 System.out.println(n.intValue()); 27 27 28 28 session.close(); 29 29 } 30 30 }
2、List集合
參考第一個HQL查詢中的內容!
3、Object[]陣列
有時候,我們不需要講實體類的所有屬性查詢出來,只需要查詢部分屬性。這時,可以將返回的內容放入Object[]中,而不是實體物件中。
1 1 String hql="select u.name,u.age from User u"; 2 2 //建立HQL查詢 3 3 Query q= session.createQuery(hql); 4 4 List<Object[]> list=q.list(); 5 5 for (int i = 0; i < list.size(); i++) { 6 6 Object[] os=list.get(i); 7 7 System.out.println("使用者名稱是:"+os[0]+"年齡是:"+os[1]); 8 8 }
顯示結果:
Hibernate: select user0_.username as col_0_0_, user0_.userage as col_1_0_ from user user0_
使用者名稱是:哈哈年齡是:18
使用者名稱是:三個年齡是:18
使用者名稱是:張三年齡是:18
使用者名稱是:李四年齡是:18
使用者名稱是:王五年齡是:18
使用者名稱是:張柳 年齡是:18
4、Map集合
我們也可以將查詢後的結果放到map中
1 1 String hql="select new map(u.name as name,u.age as age) from User u"; 2 2 //建立HQL查詢 3 3 Query q= session.createQuery(hql); 4 4 List<Map> list=q.list(); 5 5 for (int i = 0; i < list.size(); i++) { 6 6 Map map=list.get(i); 7 7 System.out.println("使用者名稱"+map.get("name")+"年齡"+map.get("age")); 8 8 } 9 9 session.close();
顯示結果:
Hibernate: select user0_.username as col_0_0_, user0_.userage as col_1_0_ from user user0_
使用者名稱哈哈年齡18
使用者名稱三個年齡18
使用者名稱張三年齡18
使用者名稱李四年齡18
使用者名稱王五年齡18
使用者名稱張柳 年齡18
5、實體物件
對於只查詢部分屬性的情況,Object陣列、Map都很方便。實際上,我們也可以通過構造方法,將查出的資料直接封裝到實體物件中。
1 1 新增構造方法: 2 2 public Emp(Short empno, String ename) { 3 3 super(); 4 4 this.empno = empno; 5 5 this.ename = ename; 6 6 } 7 7 String hql = "select new Emp(e.empno,e.ename) from Emp e "; 8 8 Query q = session.createQuery(hql); 9 9 10 10 List<Emp> list = q.list(); 11 11 for(int i=0;i<list.size();i++){ 12 12 Emp e = list.get(i); 13 13 System.out.println("僱員編號:"+e.getEmpno()+"-僱員名字"+e.getEname()); 14 14 }
6、Where子句和引數傳遞
1 1 // String hql = "from Emp where ename=?"; 2 2 String hql = "from Emp where ename=:ename"; //使用引數名稱動態繫結!(推薦使用!) 3 3 Query q = session.createQuery(hql); 4 4 // q.setString(0, "SMITH"); //引數索引從0開始計數,而不像jdbc一樣從1開始。 5 5 q.setString("ename", "SMITH"); 6 6 List list = q.list(); 7 7 for(int i=0;i<list.size();i++){ 8 8 Emp c = (Emp) list.get(i); 9 9 System.out.println(c.getEname()); 10 10 }
7、HQL分頁查詢
分頁顯示是專案中必不可少的功能,不同的資料庫有不同的分頁方式,hibernate替我們遮蔽了資料庫中之間的差異。我們通過如下簡單的程式碼即可實現分頁功能(如果分頁的原 理和做法忘記了,可以參考之前講授的專案內容)。
1 1 String hql = "from Emp"; 2 2 Query q = session.createQuery(hql); 3 3 q.setFirstResult(0); //從第幾條開始取資料 4 4 q.setMaxResults(10); //設定每頁最多顯示記錄的個數 5 5 6 6 List list = q.list(); 7 7 for(int i=0;i<list.size();i++){ 8 8 Emp c = (Emp) list.get(i); 9 9 System.out.println(c.getEname()); 10 10 }
8、跨表查詢和物件導航
SQL中複雜的表連線查詢,跨表操作。在HQL中進行了相當的簡化,我們只需要簡單的使用屬性即可,類似於我們前面學過的EL表示式。這樣,我們可以用簡單的程式碼寫出比較 複雜的查詢。
1 1 String hql = "from Emp e where e.dept.deptno=? "; 2 2 Query q = session.createQuery(hql); 3 3 q.setInteger(0, 10);
9、Join(內連線、外連線)
SQL中我們有內連線、右外連線、左外連線、全外連線,在HQL中我們也有這些概念。不過,有如下幾點不一致:
- 如果兩個實體類之間沒有任何關係,那麼不能使用join
- 由於只有兩個實體類之間有關聯關係才能使用join,因此不需要像SQL那樣通過on指明連線條件。
程式碼示例如下:
1 1 String hql = "select e.ename,d.dname from Emp e left join e.dept d "; 2 2 3 3 Query q = session.createQuery(hql);
10、SQL原生查詢(Native SQL)
有時候HQL可能不能滿足我們的要求。我們需要使用原始的SQL來完成我們的功能。我們可以通過如下方式,在hibernate中使用SQL查詢:
1 1 String sql = "select ename,sal from emp where empno=:id"; 2 2 SQLQuery q = session.createSQLQuery(sql); 3 3 q.setInteger("id", 7369); 4 4 List list = q.list(); //返回的結果為List<Object[]> 5 5 for(int i=0;i<list.size();i++){ 6 6 Object[] c = (Object[]) list.get(i); 7 7 System.out.println(c[0]+"-"+c[1]); 8 8 } 9 9 String sql = "select * from emp where empno=:id"; 10 10 SQLQuery q = session.createSQLQuery(sql); 11 11 q.setInteger("id", 7369); 12 12 q.addEntity(Emp.class); 13 13 List<Emp> list = q.list(); 14 14 for(int i=0;i<list.size();i++){ 15 15 Emp c = list.get(i); 16 16 System.out.println(c.getEname()+"-"+c.getSal()); 17 17 }