Hibernate 學習筆記(而)—— Hibernate HQL查詢和 QBC 查詢
目錄
- 一、Hibernate 的 HQL 查詢
- 1.1、查詢所有數據
- 1.2、條件查詢
- 1.3、排序查詢
- 1.4、統計查詢
- 1.5、分頁查詢
- 1.6、投影查詢
- 二、Hibernate 的 QBC 查詢
- 2.1、基本查詢
- 2.2、條件查詢
- 2.3、排序查詢
- 2.4、統計查詢
- 2.5、分頁查詢
- 2.6、投影查詢
- 2.7、離線查詢
在 Hibernate 中,查詢方式有 HQL 和 Criteria 查詢兩種方式,HQL是Hibernate Query Language的縮寫,語法類似於 SQL 語句,可以直接使用實體類名稱及屬性名稱來查詢,它提供更加豐富靈活、更為強大的查詢能力。
Criteria 查詢對查詢條件進行了面向對象封裝,符合編程人員的思維方式,不過HQL(Hibernate Query Language)查詢提供了更加豐富的和靈活的查詢特性,因此 Hibernate將 HQL 查詢方式立為官方推薦的標準查詢方式,HQL 查詢在涵蓋 Criteria 查詢的所有功能的前提下,提供了類似標準 SQL 語句的查詢方式,同時也提供了更加面向對象的封裝。
一、Hibernate 的 HQL 查詢
HQL 語法類似於 SQL,有 SQL 的關鍵詞如 select 、from 、order by 、count()、where 等,完整的HQL語句形式如下: Select/update/delete…… from …… where …… group by …… having …… order by …… asc/desc。
Hibernate 的 HQL 查詢中,通過 Session
對象的 createQuery(String HQL)
方法,獲取 Query
對象, Query
中傳入查詢的 HQL 語句,之後通過 Query
對象的 list()
方法,獲取查詢的結果集。
HQL 書寫規範:
- 在查詢語句中省略
select
關鍵字 - 使用類名稱替代數據庫中的表名稱
- 使用實體類的屬性名稱代替數據庫表中的列名稱
HQL 查詢步驟:
Query query = session.createQuery(String HQL);
:獲取查詢的Query
對象query.setParameter(arg0,arg1);
:設置查詢條件參數,參數下標從0開始List list = query.list();
:獲取查詢結果集
1.1、查詢所有數據
package com.hibernate.test;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.List;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;
import com.hibernate.domain.User;
import com.hibernate.utils.HibernateUtil;
public class TestHQL {
// 查詢數據庫表中的所有數據
@Test
public void testHQL01() {
Session session = HibernateUtil.openSession();
Transaction tx = session.beginTransaction();
tx.begin();
// 使用session的createQuery(String HQL)獲取 Query 對象
Query query = session.createQuery("from User");
// 使用 query對象的list()方法,獲取查詢結果集
List<User> list = query.list();
for (User user : list) {
System.out.println(user);
}
tx.commit();
session.close();
}
}
1.2、條件查詢
在條件查詢中,HQL 書寫方式與 SQL 一樣,使用 ?
作為參數的占位符,通過 setParameter(arg0, arg1)
來設定參數的值,其中:
arg0
:表示參數的小標,從 0 開始;arg1
:表示參數的具體值;
package com.hibernate.test;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.List;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;
import com.hibernate.domain.User;
import com.hibernate.utils.HibernateUtil;
public class TestHQL {
// 條件查詢,查詢昵稱裏面有螞蟻的用戶
@Test
public void testHQL02() {
Session session = HibernateUtil.openSession();
Transaction tx = session.beginTransaction();
tx.begin();
// 使用session的createQuery(String HQL)獲取 Query 對象
Query query = session.createQuery("from User where nickname like ?");
// 使用模糊查詢
query.setParameter(0, "%螞蟻%");
// 使用 query對象的list()方法,獲取查詢結果集
List<User> list = query.list();
for (User user : list) {
System.out.println(user);
}
tx.commit();
session.close();
}
}
1.3、排序查詢
在排序查詢中,HQL 書寫方式與 SQL 一樣,使用 order by 屬性名稱 desc/asc
來進行排序。
package com.hibernate.test;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.List;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;
import com.hibernate.domain.User;
import com.hibernate.utils.HibernateUtil;
public class TestHQL {
// 排序查詢
@Test
public void testHQL03() {
Session session = HibernateUtil.openSession();
Transaction tx = session.beginTransaction();
tx.begin();
Query query = session.createQuery("from User order by uid desc");
List<User> list = query.list();
for (User user : list) {
System.out.println(user);
}
tx.commit();
session.close();
}
}
1.4、統計查詢
在 Hibernate 中,使用 HQL 語句,也可以使用聚合函數 (count()、avg()、sum()、max()、min())
進行查詢。使用聚合函數式, HQL 語句的寫法如下:
Query query = session.createQuery("select count(*) from User");
package com.hibernate.test;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.List;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;
import com.hibernate.domain.User;
import com.hibernate.utils.HibernateUtil;
public class TestHQL {
// 統計查詢
@Test
public void testHQL04() {
Session session = HibernateUtil.openSession();
Transaction tx = session.beginTransaction();
tx.begin();
Query query = session.createQuery("select count(*) from User");
// 使用聚合函數中,除了使用 group
// by進行分組的情況下,返回的都是唯一的結果,此時可以用query的uniqueResult()方法,接收唯一結果
// 使用 Long 類型進行接收
Long count = (Long) query.uniqueResult();
System.out.println(count);
}
}
1.5、分頁查詢
在 Hibernate 的分頁查詢中,通過 query.setFirstResult(0)
和 query.setMaxResults(2)
方法分別設置查詢的開始位置和每頁顯示的數量,從而達到分頁查詢的效果。
query.setFirstResult(0)
:設置查詢的開始位置,從0開始query.setMaxResults(2)
:設置每頁的顯示數據量
package com.hibernate.test;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.List;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;
import com.hibernate.domain.User;
import com.hibernate.utils.HibernateUtil;
public class TestHQL {
// 分頁查詢
@Test
public void testHQL05() {
Session session = HibernateUtil.openSession();
Transaction tx = session.beginTransaction();
tx.begin();
Query query = session.createQuery("from User");
query.setFirstResult(0);
query.setMaxResults(2);
List<User> list = query.list();
for (User user : list) {
System.out.println(user);
}
tx.commit();
session.close();
}
}
1.6、投影查詢
在 Hibernate 框架中,當我們只需要查出某個對象中的個別屬性的時候,如目前只需要查出用戶的用戶名和密碼兩個屬性,如果使用 HQL 查詢的方式,將會查找出該對象的全部屬性,此時將會降低查詢的速度和浪費系統的資源。
如果我們使用Query query = session.createQuery(select username , password from User);
此時通過 query.list();
方法,我們得到的結果集是 List<Object[]>
類型的,不符合面向對象的特性,而且結果集不方便使用。
為了解決這一問題,Hibernate 也給出了解決方案投影查詢,通過 Query query = session.createQuery("select new User(username,password ) from User");
此時,通過 query.list()
方法得到的結果集是 list<User>
類型的,但是其中 User
對象除 username 和 password 以外的屬性均為 null。
需要註意的是:在使用投影查詢中的 HQL 語句中,出現了 new 關鍵字,這意味著,我們需要在普通Java類中添加所要查詢屬性的有參構造函數,此外,為了保證該普通 Java 類符合 JavaBean 的規範,我們需要聲明其無參構造函數,不然程序運行時會報出 org.hibernate.hql.ast.QuerySyntaxException
異常。
User 實體類
package com.hibernate.domain;
import java.util.Date;
public class User {
private Integer uid;
private String username;
private String password;
private String nickname;
private String realname;
private Date birthday;
public Integer getUid() {
return uid;
}
public void setUid(Integer uid) {
this.uid = uid;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getNickname() {
return nickname;
}
public void setNickname(String nickname) {
this.nickname = nickname;
}
public String getRealname() {
return realname;
}
public void setRealname(String realname) {
this.realname = realname;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public User(String username, String password) {
this.username = username;
this.password = password;
}
public User() {}
@Override
public String toString() {
return "User [uid=" + uid + ", username=" + username + ", password=" + password + ", nickname=" + nickname
+ ", realname=" + realname + ", birthday=" + birthday + "]";
}
}
投影查詢:
package com.hibernate.test;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.List;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;
import com.hibernate.domain.User;
import com.hibernate.utils.HibernateUtil;
public class TestHQL {
// 投影查詢:查詢用戶名和密碼
@Test
public void testHQL06() {
Session session = HibernateUtil.openSession();
Transaction tx = session.beginTransaction();
tx.begin();
Query query = session.createQuery("select new User(username, password) from User");
// 所查詢得到的結果集仍然是List<User> 類型
List<User> list = query.list();
for (User user : list) {
System.out.println(user);
}
tx.commit();
session.close();
}
}
二、Hibernate 的 QBC 查詢
Hibernate 中的 QBC 查詢方式,全稱為 Query By Criteria
,通過 Session
對象的 createCriteria(Class clazz)
方法創建 Criteria
對象,之後通過 Criteria
對象的 list()
方法獲取查詢結果集。它是一種面向對象的查詢方式,QBC 查詢把生成語句的過程全部融入到方法中了。
2.1、基本查詢
package com.hibernate.test;
import java.util.List;
import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;
import com.hibernate.domain.User;
import com.hibernate.utils.HibernateUtil;
public class TestQBC {
// 基本查詢
@Test
public void testQBC01() {
Session session = HibernateUtil.openSession();
Transaction tx = session.beginTransaction();
tx.begin();
// 使用 createCriteria(Class clazz) 創建 Criteria 對象
Criteria criteria = session.createCriteria(User.class);
List<User> list = criteria.list();
for (User user : list) {
System.out.println(user);
}
tx.commit();
session.close();
}
}
2.2、條件查詢
Hibernate QBC 查詢進行條件查詢時候,通過 Criteria
的 add()
方法,添加查詢條件。
package com.hibernate.test;
import java.util.List;
import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;
import com.hibernate.domain.User;
import com.hibernate.utils.HibernateUtil;
public class TestQBC {
// 條件查詢,通過 add()方法添加查詢條件
@Test
public void testQBC02() {
Session session = HibernateUtil.openSession();
Transaction tx = session.beginTransaction();
tx.begin();
Criteria criteria = session.createCriteria(User.class);
// 通過 Restrictions 添加具體的條件
criteria.add(Restrictions.like("nickname", "%螞蟻%"));
List<User> users = criteria.list();
for (User user : users) {
System.out.println(user);
}
tx.commit();
session.close();
}
}
2.3、排序查詢
Hibernate QBC 查詢進行排序查詢時候,通過 Criteria
的 addOrder()
方法,添加排序查詢的條件。addOrder(Order.asc(屬性名稱))
進行升序查詢和 addOrder(Order.desc(屬性名稱))
進行降序查詢
package com.hibernate.test;
import java.util.List;
import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;
import com.hibernate.domain.User;
import com.hibernate.utils.HibernateUtil;
public class TestQBC {
// 排序查詢
@Test
public void testQBC03() {
Session session = HibernateUtil.openSession();
Transaction tx = session.beginTransaction();
tx.begin();
Criteria criteria = session.createCriteria(User.class);
// 通過 addOrder() 添加排序條件
criteria.addOrder(Order.desc("uid"));
List<User> users = criteria.list();
for (User user : users) {
System.out.println(user);
}
tx.commit();
session.close();
}
}
2.4、統計查詢
QBC 查詢中,Criteria
通過 criteria.setProjection(Projections.XXX)
方法來設定聚合函數。如使用 Projections.rowCount()
獲取數據表中的總記錄數,通過 Projections.count("實體類屬性名稱")
獲取該屬性有屬性值的數據條記錄數。
package com.hibernate.test;
import java.util.List;
import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;
import com.hibernate.domain.User;
import com.hibernate.utils.HibernateUtil;
public class TestQBC {
// 統計查詢
@Test
public void testQBC04() {
Session session = HibernateUtil.openSession();
Transaction tx = session.beginTransaction();
tx.begin();
Criteria criteria = session.createCriteria(User.class);
// 獲取數據庫表中具有uid屬性值的數據條數
criteria.setProjection(Projections.count("uid"));
Long count = (Long) criteria.uniqueResult();
System.out.println(count);
tx.commit();
session.close();
}
}
2.5、分頁查詢
QBC 和 HQL 中的分頁查詢所用的方法和方法的含義是一模一樣的。通過 query.setFirstResult(0)
和 query.setMaxResults(2)
方法分別設置查詢的開始位置和每頁顯示的數量,從而達到分頁查詢的效果。
query.setFirstResult(0)
:設置查詢的開始位置,從0開始query.setMaxResults(2)
:設置每頁的顯示數據量
package com.hibernate.test;
import java.util.List;
import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;
import com.hibernate.domain.User;
import com.hibernate.utils.HibernateUtil;
public class TestQBC {
// 分頁查詢
@Test
public void testQBC05() {
Session session = HibernateUtil.openSession();
Transaction tx = session.beginTransaction();
tx.begin();
Criteria criteria = session.createCriteria(User.class);
// 設置分頁條件
criteria.setFirstResult(0);
criteria.setMaxResults(2);
List<User> users = criteria.list();
for (User user : users) {
System.out.println(user);
}
tx.commit();
session.close();
}
}
2.6、投影查詢
package com.hibernate.test;
import java.util.List;
import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;
import com.hibernate.domain.User;
import com.hibernate.utils.HibernateUtil;
public class TestQBC {
// 投影查詢
@Test
public void testQBC06() {
Session session = HibernateUtil.openSession();
Transaction tx = session.beginTransaction();
tx.begin();
Criteria criteria = session.createCriteria(User.class);
// 通過Projections.projectionList().add()添加所要查詢的屬性名
criteria.setProjection(
Projections.projectionList().add(Property.forName("username")).add(Property.forName("password")));
List<User> users = criteria.list();
for (User user : users) {
System.out.println(user);
}
tx.commit();
session.close();
}
}
2.7、離線查詢
在 JavaWeb 項目中,客戶端查詢實體總共經以下步驟:
- 客戶端提交查詢條件;
- 表現層 servlet 接收到客戶端提交的查詢條件,開啟
Session
和Transaction
,創建Criteria
對象,將查詢條件封裝到所創建的criteria
對象中,並將criteria
對象傳遞到業務層; - 業務層將接收的
criteria
對象傳遞給持久層; - 持久層接收
criteria
對象,查詢數據庫,並將查詢結果依次傳遞給業務層、表現層,最後傳遞到客戶端;
存在問題:
此時發現,在表現層中出現了開啟 Session
和 Transaction
,創建 Criteria
對象等屬於持久層的操作,不符合 MVC
的程序設計規範,對後期程序的維護造成壓力;
解決方式:使用 QBC 查詢的離線查詢,創建 DetachedCriteria
對象,該對象的獲取不需要 Session
,可以直接獲得。
- 客戶端提交查詢條件,
- 表現層 servlet 接收到客戶端提交的查詢條件,創建
DetachedCriteria
對象,封裝查詢條件;並將criteria
對象傳遞到業務層; - 業務層將接收的
DetachedCriteria
對象傳遞給持久層; - 持久層接收
DetachedCriteria
對象,將其轉化成為Criteria
對象,查詢數據庫,並將查詢結果依次傳遞給業務層、表現層,最後傳遞到客戶端;
package com.hibernate.test;
import java.util.List;
import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;
import com.hibernate.domain.User;
import com.hibernate.utils.HibernateUtil;
public class TestQBC {
// 模擬表現層 —— Servlet
@Test
public void servletDetachedCriteria() {
// 創建DetachedCriteria對象
DetachedCriteria dc = DetachedCriteria.forClass(User.class);
// 封裝客戶端提交的查詢條件
dc.add(Restrictions.like("nickname", "%螞蟻%"));
// 將封裝好查詢條件的DetachedCriteria對象傳遞給業務層
List<User> users = seviceDetachedCriteria(dc);
for (User user : users) {
System.out.println(user);
}
}
// 模擬業務層代碼
public List seviceDetachedCriteria(DetachedCriteria dc) {
Session session = null;
Transaction tx = null;
try {
// 獲取與當前線程綁定的 Session 對象
session = HibernateUtil.getCurrentSession();
tx = session.beginTransaction();
tx.begin();
return daoDetachedCriteria(dc);
} catch (Exception e) {
tx.rollback();
} finally {
tx.commit();
}
return null;
}
// 模擬持久層代碼
public List daoDetachedCriteria(DetachedCriteria dc) {
// 獲取當前線程綁定的session
Session session = HibernateUtil.getCurrentSession();
// 將業務層傳遞的DetachedCriteria對象轉化為Criteria對象
Criteria criteria = dc.getExecutableCriteria(session);
// 返回查詢結果集
return criteria.list();
}
}
Hibernate 學習筆記(而)—— Hibernate HQL查詢和 QBC 查詢