Hibernate總的來說共有四種查詢方式:HQL、QBC、QBE和SQL四種。但是細分可以有如下幾種:
一、HQL查詢方式
這一種我最常用,也是最喜歡用的,因為它寫起來靈活直覺,而且與所熟悉的SQL的文法差不太多。條件查詢、分頁查詢、連接配接查詢、嵌套查詢,寫起來與SQL文法基本一緻,唯一不同的就是把表名換成了類或者對象。其它的,包括一些查詢函數(count(),sum()等)、查詢條件的設定等,全都跟SQL文法一樣。在這裡需要提醒一下的是: 在hql中關鍵字不區分大小寫,但是屬性和類名區分大小寫
示例1:
static void query(String name){
Session s=null;
try{
s=HibernateUtil.getSession();
//from後面是對象,不是表名
String hql="from Admin as admin where admin.aname=:name";//使用命名參數,推薦使用,易讀。
Query query=s.createQuery(hql);
query.setString("name", name);
List<Admin> list=query.list();
for(Admin admin:list){
System.out.println(admin.getAname());
}
}finally{
if(s!=null) s.close();
}
}
######!!!!!!!!!!!!!對于多對一關系查詢:
String hql = "from Student whereClass.className = '微機76班'";
(Student實體類中含有Class對象的引用。這樣相當于兩張表的聯合查詢)
示例2(分頁查詢):
Query query = session.createQuery("from Customer c
order by c.name asc");
query.setFirstResult(0);
query.setMaxResults(10);
List result = query.list();
說明:
–setFirstResult(int firstResult):設定從哪一個對象開始檢索,參數firstResult表示這個對象在查詢結果中的索引位置,索引位置的起始值為0。預設情況下,Query和Criteria接口從查詢結果中的第一個對象,也就是索引位置為0的對象開始檢索。
–setMaxResult(int maxResults):設定一次最多檢索出的對象數目。預設情況下,Query和Criteria接口檢索出查詢結果中所有的對象。
适用情況:常用方法,比較傳統,類似jdbc。缺點:新的查詢語言,适用面有限,僅适用于Hibernate架構。
二、QBC(Query By Criteria) 查詢方式
這種方式比較面向對象方式,重點是有三個描述條件的對象:Restrictions,Order,Projections。使用QBC查詢,一般需要以下三個步驟:
1、 使用Session執行個體的createCriteria()方法建立Criteria對象
2、使用工具類Restrictions的方法為Criteria對象設定查詢條件,Order工具類的方法設定排序方式,Projections工具類的方法進行統計和分組。
3、使用Criteria對象的list()方法進行查詢并傳回結果
Restrictions類的常用方法:
Restrictions類的常用方法:
方法名稱 | 描述 |
Restrictions.eq | 等于 |
Restrictions.allEq | 使用Map,Key/Valu進行多個等于的比對 |
Restrictions.gt | 大于 |
Restrictions.ge | 大于等于 |
Restrictions.lt | 小于 |
Restrictions.le | 小于等于 |
Restrictions.between | 對應SQL的between |
Restrictions.like | 對應SQL的like |
Restrictions.in | 對應SQL的in |
Restrictions.and | and關系 |
Restrictions.or | or關系 |
Restrictions.sqlRestriction | SQL限定查詢 |
Order類的常用方法:
方法名稱 | 描述 |
Order.asc | 升序 |
Order.desc | 降序 |
Projections類的常用方法
方法名稱 | 描述 |
Projections.avg | 求平均值 |
Projections.count | 統計某屬性的數量 |
Projections.countDistinct | 統計某屬性不同值的數量 |
Projections.groupProperty | 指定某個屬性為分組屬性 |
Projections.max | 求最大值 |
Projections.min | 求最小值 |
Projections.projectionList | 建立一個ProjectionList對象 |
Projections.rowCount | 查詢結果集中的記錄條數 |
Projections.sum | 求某屬性的合計 |
示例:static void cri(String name,String password){
Session s=null;
try{
s=HibernateUtil.getSession();
Criteria c=s.createCriteria(Admin.class);
c.add(Restrictions.eq("aname",name));//eq是等于,gt是大于,lt是小于,or是或
c.add(Restrictions.eq("apassword", password));
List<Admin> list=c.list();
for(Admin admin:list){
System.out.println(admin.getAname());
}
}finally{
if(s!=null) s.close();
}
}
示例2(分頁查詢):
Criteria criteria = session.createCriteria(Customer.class);
criteria.addOrder( Order.asc("name") ); //排序方式
criteria.setFirstResult(0);
criteria.setMaxResults(10);
List result = criteria.list()
适用情況:面向對象操作,革新了以前的資料庫操作方式,易讀。缺點:适用面較HQL有限。
三、QBE(Query By Example)例子查詢方式
将一個對象的非空屬性作為查詢條件進行查詢。
示例:Session session = SessionFactory.getCurrentSession();
User user = new User();
user.setName("ijse");
Transaction ts = session.beginTransaction();
try {
Criteria criteria = session.createCriteria(User.class);
criteria.add(Example.create(user));
user= (User) criteria.list().get(0);
session.commit();
} catch (HibernateException ex) {
ts.rollBack();
ex.printStackTrace();
}
System.out.println(user.getName());
适用情況:面向對象操作。 缺點:适用面較HQL有限,不推薦。
四、DetachedCriteria:離線條件查詢
離線查詢就是建立一個DetachedCriteria對象,将查詢的條件等指定好,然後在session.beginTransaction()後将這個對象傳入。通常這個對象可以在表示層建立,然後傳入業務層進行查詢。
1、建立DetachedCriteria對象
DetachedCriteria dc = DetachedCriteria.forClass(User.class);
int id = 1;
if (id != 0)
dc.add(Restrictions.eq("id", id));
Date age = new Date();
if (age != null)
dc.add(Restrictions.le("birthday", age));
List users = dc(dc);//執行查詢
System.out.println("離線查詢傳回結果:" + users);
2、執行查詢
static List dc(DetachedCriteria dc) {
Session s = HibernateUtil.getSession();
Criteria c = dc.getExecutableCriteria(s);
List rs = c.list();
s.close();
return rs;
}
适用情況:面向對象操作,分離業務與底層,不需要字段屬性攝入到Dao實作層。 缺點:适用面較HQL有限。
五、命名查詢
1、在資料映射元檔案中進行配置如下:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="com.sy.vo.User" table="user" catalog="news">
....
</class>
<!-- 命名查詢:定義查詢條件 -->
<query name="getUserById">
<![CDATA[from User where id=:id]]>
</query>
<!-- 命名查詢中使用sql,不推薦使用,影響跨資料庫
<sql-query name="getUserById2">
<![CDATA[select * from User where ]]>
</sql-query> -->
</hibernate-mapping>
2、在java代碼中寫入:
static List namedQuery(int id) {
Session s = HibernateUtil.getSession();
Query q = s.getNamedQuery("getUserById");
q.setInteger("id", id);
return q.list();
}
适用情況:萬能方法,有點像ibatis輕量級架構的操作,友善維護。 缺點:不面向對象。基于hql和sql,有一定缺陷。
六、SQL查詢
示例:
static List sql() {
Session s = HibernateUtil.getSession();
Query q = s.createSQLQuery("select * from user").addEntity(User.class);
List<User> rs = q.list();
s.close();
return rs;
}
适用情況:不熟悉HQL的朋友,又不打算轉資料庫平台的朋友,萬能方法 缺點:破壞跨平台,不易維護,不面向對象。
七、OID查詢方式
按照對象的OID來檢索對象。Session的get()和load()方法提供了這種功能。如果在應用程式中事先知道了OID,就可以使用這種檢索對象的方式。
八、Query.iterator的N+1查詢(基于一的HQL,多見于一對多、多對多的關聯映射)
N + 1問題,在預設情況下,使用query.iterate查詢,有可以能出現N+1問題
所謂的N+1是在查詢的時候發出了N+1條sql語句
1: 首先發出一條查詢對象id清單的sql
N: 根據id清單到緩存中查詢,如果緩存中不存在與之比對的資料,那麼會根據id發出相應的sql語句
* list和iterate的差別?
* list每次都會發出sql語句,list會向緩存中放入資料,而不利用緩存中的資料
* iterate:在預設情況下iterate利用緩存資料,但如果緩存中不存在資料有可以能出現N+1問題
示例:Query q=session.createQuery(“from UserInfo”);
Iterator<UserInfo> list=q.iterate();
While(list.hasNext()) {
UserInfo st = (UserInfo) it.next();
System.out.println(st.getName());
}
避免N+1查詢解決方法:
1、可以将fetch抓取資料的屬性改為“join”,來避免N+1次的查詢;
2、使用二級緩存
九、複查查詢(基于二:QBC的深度查詢)
複合查詢就是在原有查詢的基礎上再進行查詢,可以調用Criteria對象的createCriteria()方法在這個Criteria對象的基礎上再進行查詢。
示例:Session session = SessionFactory.getCurrentSession();
User user = new User();
Transaction ts = session.beginTransaction();
try {
Criteria criteria1 = session.createCriteria(Room.class);
Criteria criteria2 =criterial.createCriteria("User");
criteria2.add(Restrictions.eq("name",new String("ijse"));
user= (User) criteria.list().get(0);
session.commit();
} catch (HibernateException ex) {
ts.rollBack();
ex.printStackTrace();
}
System.out.println(user.getName());
最後,再說一下,Hibernate是可以執行存儲過程的。相關的文章我會在後續的文章中給出,請大家繼續關注.