Hibernate 中的 Criteria 查詢
1. 前言
今天給大家介紹一個絕對純正的 OOP 查詢方案:Criteria 查詢。通過本節課程的內容,你將了解到:
- 什么是 Criteria 查詢
- Criteria 實現復雜查詢;
2. Criteria 查詢
什么是 Criteria 查詢?
Criteria 查詢從字面翻譯就是標準查詢。所謂 標準查詢,指的是 HIbernate 提供了純正的 OOP API 查詢方案。不像 HQL 還摻雜了一些 SQL 層面的內容。
來一個查詢需求:查詢所有的學生。
想必這學生會很生氣,總是被搬來搬去的。
上實例之前,先認識 Hibernate 兄弟會中的一名新成員:Criteria。
在使用 Criteria 查詢之前,必須先創建 Criteria 對象:
Criteria cr = session.createCriteria(Student.class);
List<Student> stus = cr.list();
是不是很 OOP。使用 HQL 時,會有一種時空穿越的感覺 ,OOP 和 SQL 語法交替出現,很容易犯暈。使用 Criteria 進行查詢時則不會。
而且,Criteria 不是一個人在戰斗,它也有屬于自己的兄弟會,為開發者提供了更強有力的支持。
先介紹一下它的幾個兄弟,并且它們的作用已經從字面告訴了你。
- Criterion: 這位兄弟長得好生面熟,其實它就 Criteria 的單數存在形式;
- Oder: 提供排序功能;
- Restrictions: 限制、約束的意思,和 SQL 中的 where 關鍵字的作用是一樣。所以,它提供了很多類似于運算符的方法,可以對查詢數據進行過濾。
Criteria 面子上很 OOP ,但是無論你怎么逃,都是在 SQL 的手掌心,也就是說 Criteria 查詢最終還是會被 Hibernate 轉譯成 SQL 語句。
只要是使用關系型數據庫,SQL 就是逃不掉的宿命。只是直接、間接使用的區別。
所以,Criteria 查詢中總會找到 SQL 的影子。
2.1 基礎查詢
為了更好地理解它們,來一個實例:查詢姓名叫 “Hibernate” 的學生。
Criteria criteria = session.createCriteria(Student.class);
Criterion criterion = Restrictions.eq("stuName", "Hibernate");
criteria.add(criterion);
Student student = (Student) criteria.uniqueResult();
System.out.println(student);
Criteria 查詢封裝了關系型數據庫的概念,所以,一定要注意,使用方法進行數據過濾時,都是屬性進行比較。
確認查詢出來的數據只有一條記錄時,可以使用 uniqueResult() 方法。條件查詢的關鍵是了解 Restrictions,它所提供的很多類似于邏輯運算符的方法:
- Restrictions.eq(): 相當于 =;
- Restrictions.not(Exprission.eq()) : 相當于 <>;
- Restrictions.le(): 相當于 <=;
- Restrictions.gt(): 相當于 >;
- Restrictions.ge(): 相當于 >=;
- Restrictions.lt(): 相當于 <;
- Restrictions.isnull(): 相當于 is null;
- Restrictions.isNotNull(): 相當于 is not null ;
- Restrictions.like(): 相當于 like;
- Restrictions.and(): 相當于 and;
- Restrictions.conjunction(): 相當于 and;
- Restrictions.or(): 相當于 or;
- Restrictions.disjunction() : 相當于 or;
- Restrictions.not(): 相當于 not;
- Restrictions.in(): 相當于 in;
- Restrictions.not(Restrictions.in()): 相當于 not in;
- Restrictions.between(): 相當于 between x and y;
- Restrictions.not(Restrictions…between()) : 相當于 not between x and y。
如上方法,幾乎涵蓋了所有 SQL 條件運算符,任意組合上面方法,沒有查詢不出來的結果。
如查詢學生編號是 1 或 2 或 4 的學生。
使用 SQL,則是:
select * from student where stuId in (1,2,4)
使用 Criteria 查詢,則如下所示:
Criterion criterion = Restrictions.in("stuId",new Integer[] {1,2,4} );
criteria.add(criterion);
如查詢學生編號大于 2 且班級編號為 1 的學生。
使用 SQL:
select * from student where stuId>2 and classRommId=1
如果使用 Criteria 查詢,則先構建兩個約束對象:
Criterion criterion = Restrictions.gt("stuId", 2);
Criterion criterion1 = Restrictions.eqOrIsNull("classRoom.classRoomId", 1);
再把這兩個約束作為參數,構建一條聯合約束:
LogicalExpression logicalExpression = Restrictions.and(criterion, criterion1);
criteria.add(logicalExpression);
LogicalExpression API 用來表示一個邏輯表達式。是 Criterion 的子類。
比較原生 SQL 和 Criteria 查詢,會發現原生 SQL 語句要簡單很多,使用 Criteria 查詢需要掌握很多 API,而且代碼量也比較大,這也可能是 Criteria 查詢得不到普及的原因吧。
但是,Hibernate 既然推出了這種查詢方案,想必也有它的考慮。比如說,創建動態查詢語句,這點原生 SQL 或 HQL 都沒有 Criteria 好。
還是那句話,存在就是合理的。
如果,你對原生 SQL 有情懷,Criteria 查詢中也是可以用的。
criteria.add( Restrictions.sqlRestriction("stuId>2 and clasRoomId=1"));
注意,不要在 Sql 片段中使用 where 關鍵字。既然是原生 SQL,所以語句中是字段概念,而不是屬性概念。
前面講解 HQL 時,提到了分頁查詢。Criteria 一樣可以實現分頁查詢,和 HQL 中分頁方法一樣:
Criteria criteria = session.createCriteria(Student.class);
criteria.setFirstResult(1);
criteria.setMaxResults(5);
List results = criteria.list();
2.2 高級查詢
排序查詢使用 order API 實現:
criteria.addOrder(Order.desc("stuId"));
criteria.addOrder(Order.asc("stuName"));
一樣,可以多字段排序。
使用聚合函數:聚合函數的功能封裝在 projections API 中:
criteria.setProjection(Projections.rowCount());
criteria.setProjection(Projections.avg("stuId"));
criteria.setProjection(Projections.max("stuId"));
criteria.setProjection(Projections.min("stuId"));
criteria.setProjection(Projections.sum("stuId"));
Criteria 也能實現關聯查詢:
Criteria criteria = session.createCriteria(Student.class);
criteria.add(Restrictions.like("stuName", "Hibernate%"));
Criteria criteria01 = criteria.createCriteria("classRoom");
criteria01.add(Restrictions.like("classRoomName", "c19%"));
List<Student> students = criteria.list();
可以把一個 Criteria 實例看成對一張表的查詢,如果需要關聯多張表,則可以通過一個 Criteria 再創建一個 Criteria 對象。
Hibernate 為 Criteria 查詢提供各種各樣的 API,適應于任何查詢需求,相比較使用的已經很普遍的 SQL 查詢,Criteria 查詢充滿了雞肋的味道。但對于動態查詢需求,Criteria 查詢的優勢又很明顯。
3. 原生 SQL 查詢
Hibernate 支持原生 SQL 查詢,對于熟悉并鐘情于 SQL 語句的開發者來講,是一個很大的福音。
實例:
String sql="select * from student";
SQLQuery sqlQuery= session.createSQLQuery(sql);
Hibernate 提供了一個與原生 SQL 有關的 SQLQuery 對象。SQLQuery 是 Query 的子類,可適應不同的原生 SQL 語句查詢。
4. 小結
本節課和大家聊到了 Criteria 查詢,HQL 查詢,原生 SQL 查詢。原生 SQL 查詢無所不能,HQL 查詢是面向對象的 SQL ,具有混血身份。據說,混血的總是很美,也是建議大家選擇的一種查詢方案。
Criteria 查詢是 Hibernate 提供的一種純面向對象的解決方案,但是,為了構建一條 SQL 語句需要寫許多代碼,其應用領域會相對較窄。
本節課給大家介紹 Criteria 的目的,一是擴展學生的學習范圍,如果需要使用動態查詢,Criteria 則有著無可比擬的優越感。