(四)Hibernate之三大類查詢總結

 Hibernate目前總共分爲三大類查詢:cretiria,hql,本地sql 【以下篇章蒐集於網絡,感謝作者】

第一:關於cretiria的查詢

   具有一個直觀的、可擴展的條件查詢API是Hibernate的特色。

15.1. 創建一個Criteria 實例
org.hibernate.Criteria接口表示特定持久類的一個查詢。Session是 Criteria實例的工廠。

Java代碼  收藏代碼
  1. <span style="font-size: medium;">Criteria crit = sess.createCriteria(Cat.class);  
  2. crit.setMaxResults(50);  
  3. List cats = crit.list();</span>  

 
15.2. 限制結果集內容
一個單獨的查詢條件是org.hibernate.criterion.Criterion 接口的一個實例。org.hibernate.criterion.Restrictions類 定義了獲得某些內置Criterion類型的工廠方法。

Java代碼  收藏代碼
  1. <span style="font-size: medium;">List cats = sess.createCriteria(Cat.class)  
  2.      .add( Restrictions.like("name""Fritz%") )  
  3.      .add( Restrictions.between("weight", minWeight, maxWeight) )  
  4.      .list();  
  5. </span>  

 
約束可以按邏輯分組。

Java代碼  收藏代碼
  1. <span style="font-size: medium;">List cats = sess.createCriteria(Cat.class)  
  2.      .add( Restrictions.like("name""Fritz%") )  
  3.      .add( Restrictions.or(  
  4.          Restrictions.eq( "age"new Integer(0) ),  
  5.          Restrictions.isNull("age")  
  6.      ) )  
  7.      .list();  
  8. List cats = sess.createCriteria(Cat.class)  
  9.      .add( Restrictions.in( "name"new String[] { "Fritz""Izi""Pk" } ) )  
  10.      .add( Restrictions.disjunction()  
  11.          .add( Restrictions.isNull("age") )  
  12.       .add( Restrictions.eq("age"new Integer(0) ) )  
  13.       .add( Restrictions.eq("age"new Integer(1) ) )  
  14.       .add( Restrictions.eq("age"new Integer(2) ) )  
  15.      ) )  
  16.      .list();</span>  

 
Hibernate提供了相當多的內置criterion類型(Restrictions 子類), 但是尤其有用的是可以允許你直接使用SQL。

 

Java代碼  收藏代碼
  1. <span style="font-size: medium;">List cats = sess.createCriteria(Cat.class)  
  2.      .add( Restrictions.sql("lower({alias}.name) like lower(?)""Fritz%", Hibernate.STRING) )  
  3.      .list();  
  4. </span>  

 


{alias}佔位符應當被替換爲被查詢實體的列別名。

Property實例是獲得一個條件的另外一種途徑。你可以通過調用Property.forName() 創建一個Property。

Java代碼  收藏代碼
  1. <span style="font-size: medium;">Property age = Property.forName("age");  
  2. List cats = sess.createCriteria(Cat.class)  
  3.      .add( Restrictions.disjunction()  
  4.          .add( age.isNull() )  
  5.       .add( age.eq( new Integer(0) ) )  
  6.       .add( age.eq( new Integer(1) ) )  
  7.       .add( age.eq( new Integer(2) ) )  
  8.      ) )  
  9.      .add( Property.forName("name").in( new String[] { "Fritz""Izi""Pk" } ) )  
  10.      .list();</span>  

 
15.3. 結果集排序
你可以使用org.hibernate.criterion.Order來爲查詢結果排序。

Java代碼  收藏代碼
  1. <span style="font-size: medium;">List cats = sess.createCriteria(Cat.class)  
  2.      .add( Restrictions.like("name""F%")  
  3.      .addOrder( Order.asc("name") )  
  4.      .addOrder( Order.desc("age") )  
  5.      .setMaxResults(50)  
  6.      .list();  
  7. List cats = sess.createCriteria(Cat.class)  
  8.      .add( Property.forName("name").like("F%") )  
  9.      .addOrder( Property.forName("name").asc() )  
  10.      .addOrder( Property.forName("age").desc() )  
  11.      .setMaxResults(50)  
  12.      .list();  
  13. </span>  

 

15.4. 關聯
你可以使用createCriteria()非常容易的在互相關聯的實體間建立 約束。 
 

Java代碼  收藏代碼
  1. <span style="font-size: medium;">List cats = sess.createCriteria(Cat.class)  
  2.      .add( Restrictions.like("name""F%")  
  3.      .createCriteria("kittens")  
  4.          .add( Restrictions.like("name""F%")  
  5.      .list();  
  6. </span>  

 

注意第二個 createCriteria()返回一個新的 Criteria實例,該實例引用kittens 集合中的元素。

接下來,替換形態在某些情況下也是很有用的。

Java代碼  收藏代碼
  1. <span style="font-size: medium;">List cats = sess.createCriteria(Cat.class)  
  2.      .createAlias("kittens""kt")  
  3.      .createAlias("mate""mt")  
  4.      .add( Restrictions.eqProperty("kt.name""mt.name") )  
  5.      .list();  
  6. </span>  

 

(createAlias()並不創建一個新的 Criteria實例。)

Cat實例所保存的之前兩次查詢所返回的kittens集合是 沒有被條件預過濾的。如果你希望只獲得符合條件的kittens, 你必須使用returnMaps()。

Java代碼  收藏代碼
  1. <span style="font-size: medium;">List cats = sess.createCriteria(Cat.class)  
  2.      .createCriteria("kittens""kt")  
  3.          .add( Restrictions.eq("name""F%") )  
  4.      .returnMaps()  
  5.      .list();  
  6. Iterator iter = cats.iterator();  
  7. while ( iter.hasNext() ) {  
  8.      Map map = (Map) iter.next();  
  9.      Cat cat = (Cat) map.get(Criteria.ROOT_ALIAS);  
  10.      Cat kitten = (Cat) map.get("kt");  
  11. }  
  12. </span>  

 

15.5. 動態關聯抓取
你可以使用setFetchMode()在運行時定義動態關聯抓取的語義。

Java代碼  收藏代碼
  1. <span style="font-size: medium;">List cats = sess.createCriteria(Cat.class)  
  2.      .add( Restrictions.like("name""Fritz%") )  
  3.      .setFetchMode("mate", FetchMode.EAGER)  
  4.      .setFetchMode("kittens", FetchMode.EAGER)  
  5.      .list();  
  6. </span>  

 

這個查詢可以通過外連接抓取mate和kittens。 查看第 19.1 節 “ 抓取策略(Fetching strategies) ”可以獲得更多信息。

15.6. 查詢示例
org.hibernate.criterion.Example類允許你通過一個給定實例 構建一個條件查詢。

Java代碼  收藏代碼
  1. <span style="font-size: medium;">Cat cat = new Cat();  
  2. cat.setSex('F');  
  3. cat.setColor(Color.BLACK);  
  4. List results = session.createCriteria(Cat.class)  
  5.      .add( Example.create(cat) )  
  6.      .list();</span>  

 
版本屬性、標識符和關聯被忽略。默認情況下值爲null的屬性將被排除。

你可以自行調整Example使之更實用。

Java代碼  收藏代碼
  1. <span style="font-size: medium;">Example example = Example.create(cat)  
  2.      .excludeZeroes()            //exclude zero valued properties  
  3.      .excludeProperty("color")   //exclude the property named "color"  
  4.      .ignoreCase()               //perform case insensitive string comparisons  
  5.      .enableLike();              //use like for string comparisons  
  6. List results = session.createCriteria(Cat.class)  
  7.      .add(example)  
  8.      .list();</span>  

 
你甚至可以使用examples在關聯對象上放置條件。

Java代碼  收藏代碼
  1. <span style="font-size: medium;">List results = session.createCriteria(Cat.class)  
  2.      .add( Example.create(cat) )  
  3.      .createCriteria("mate")  
  4.          .add( Example.create( cat.getMate() ) )  
  5.      .list();  
  6. </span>  

 

15.7. 投影(Projections)、聚合(aggregation)和分組(grouping)
org.hibernate.criterion.Projections是 Projection 的實例工廠。我們通過調用 setProjection()應用投影到一個查詢。

在一個條件查詢中沒有必要顯式的使用 "group by" 。某些投影類型就是被定義爲 分組投影,他們也出現在SQL的group by子句中。

你可以選擇把一個別名指派給一個投影,這樣可以使投影值被約束或排序所引用。下面是兩種不同的實現方式:

Java代碼  收藏代碼
  1. <span style="font-size: medium;">List results = session.createCriteria(Cat.class)  
  2.      .setProjection( Projections.alias( Projections.groupProperty("color"), "colr" ) )  
  3.      .addOrder( Order.asc("colr") )  
  4.      .list();  
  5. List results = session.createCriteria(Cat.class)  
  6.      .setProjection( Projections.groupProperty("color").as("colr") )  
  7.      .addOrder( Order.asc("colr") )  
  8.      .list();  
  9. </span>  

 

alias()和as()方法簡便的將一個投影實例包裝到另外一個 別名的Projection實例中。簡而言之,當你添加一個投影到一個投影列表中時 你可以爲它指定一個別名:

Java代碼  收藏代碼
  1. <span style="font-size: medium;">List results = session.createCriteria(Cat.class)  
  2.      .setProjection( Projections.projectionList()  
  3.          .add( Projections.rowCount(), "catCountByColor" )  
  4.          .add( Projections.avg("weight"), "avgWeight" )  
  5.          .add( Projections.max("weight"), "maxWeight" )  
  6.          .add( Projections.groupProperty("color"), "color" )  
  7.      )  
  8.      .addOrder( Order.desc("catCountByColor") )  
  9.      .addOrder( Order.desc("avgWeight") )  
  10.      .list();  
  11. List results = session.createCriteria(Domestic.class"cat")  
  12.      .createAlias("kittens""kit")  
  13.      .setProjection( Projections.projectionList()  
  14.          .add( Projections.property("cat.name"), "catName" )  
  15.          .add( Projections.property("kit.name"), "kitName" )  
  16.      )  
  17.      .addOrder( Order.asc("catName") )  
  18.      .addOrder( Order.asc("kitName") )  
  19.      .list();</span>  

 
你也可以使用Property.forName()來表示投影:

Java代碼  收藏代碼
  1. <span style="font-size: medium;">List results = session.createCriteria(Cat.class)  
  2.      .setProjection( Property.forName("name") )  
  3.      .add( Property.forName("color").eq(Color.BLACK) )  
  4.      .list();  
  5. List results = session.createCriteria(Cat.class)  
  6.      .setProjection( Projections.projectionList()  
  7.          .add( Projections.rowCount().as("catCountByColor") )  
  8.          .add( Property.forName("weight").avg().as("avgWeight") )  
  9.          .add( Property.forName("weight").max().as("maxWeight") )  
  10.          .add( Property.forName("color").group().as("color" )  
  11.      )  
  12.      .addOrder( Order.desc("catCountByColor") )  
  13.      .addOrder( Order.desc("avgWeight") )  
  14.      .list();</span>  

 
15.8. 離線(detached)查詢和子查詢
DetachedCriteria類使你在一個session範圍之外創建一個查詢,並且可以使用任意的 Session來執行它。

Java代碼  收藏代碼
  1. <span style="font-size: medium;">DetachedCriteria query = DetachedCriteria.forClass(Cat.class)  
  2.      .add( Property.forName("sex").eq('F') );  
  3.       
  4. Session session = ....;  
  5. Transaction txn = session.beginTransaction();  
  6. List results = query.getExecutableCriteria(session).setMaxResults(100).list();  
  7. txn.commit();  
  8. session.close();  
  9. DetachedCriteria也可以用以表示子查詢。條件實例包含子查詢可以通過 Subqueries或者Property獲得。   
  10.   
  11. DetachedCriteria avgWeight = DetachedCriteria.forClass(Cat.class)  
  12. .setProjection( Property.forName("weight").avg() );  
  13. session.createCriteria(Cat.class)  
  14. .add( Property.forName("weight).gt(avgWeight) )  
  15. .list();  
  16. DetachedCriteria weights = DetachedCriteria.forClass(Cat.class)  
  17. .setProjection( Property.forName("weight") );  
  18. session.createCriteria(Cat.class)  
  19. .add( Subqueries.geAll("weight", weights) )  
  20. .list();</span>  

 
甚至相互關聯的子查詢也是有可能的:

Java代碼  收藏代碼
  1. <span style="font-size: medium;">DetachedCriteria avgWeightForSex = DetachedCriteria.forClass(Cat.class"cat2")  
  2. .setProjection( Property.forName("weight").avg() )  
  3. .add( Property.forName("cat2.sex").eqProperty("cat.sex") );  
  4. session.createCriteria(Cat.class"cat")  
  5. .add( Property.forName("weight).gt(avgWeightForSex) )  
  6. .list();</span>  

 

 

第二:HQL查詢

在HQL中關鍵字不區分大小寫,但是屬性和類名區分大小寫,下面介紹各種類型的Hibernate的HQL查詢。
1、Hibernate HQL查詢:簡單屬性查詢

* 單一屬性查詢,返回結果集屬性列表,元素類型和實體類中相應的屬性類型一致

* 多個屬性查詢,返回的集合元素是對象數組,數組元素的類型和對應的屬性在實體類中的類型一致
數組的長度取決與select中屬性的個數

* 如果認爲返回數組不夠對象化,可以採用HQL動態實例化Student對象

2、Hibernate 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問題

3、Hibernate HQL查詢:條件查詢

* 可以採用拼字符串的方式傳遞參數

Java代碼:

Java代碼  收藏代碼
  1. <span style="font-size: medium;">List students = session.createQuery("select s.id, s.name from Student s where s.name like '%1%'").list();   </span>  

 

* 可以採用 ?來傳遞參數(索引從0開始)

Java代碼:

Java代碼  收藏代碼
  1. <span style="font-size: medium;">List students = session.createQuery("select s.id, s.name from Student s where s.name like ?").setParameter(0"%1%").list();      //可以使用?方式傳遞參數      //參數的索引從0開始      //傳遞的參數值,不用單引號引起來      //注意方法鏈編程    </span>  

  

* 可以採用 :參數名 來傳遞參數

Java代碼:

 

Java代碼  收藏代碼
  1. <span style="font-size: medium;">List students = session.createQuery  ("select s.id, s.name from Student s where s.name like :myname").setParameter("myname""%1%").list();    </span>  

 

* 如果傳遞多個參數,可以採用setParamterList方法

Java代碼: 

    

Java代碼  收藏代碼
  1. <span style="font-size: medium;">List students = session.createQuery("select s.id, s.name from Student s where s.id in(:myids)").setParameterList("myids"new Object[]{12345}).list();</span>  

 

* 在HQL中可以使用數據庫的函數,如:date_format

Java代碼:

Java代碼  收藏代碼
  1. <span style="font-size: medium;">List students = session.createQuery("select s.id, s.name from Student s where date_format(s.createTime, '%Y-%m')=?").setParameter(0"2008-02").list();      SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");                  //查詢2008-01-10到2008-02-15創建的學生          List students = session.createQuery("select s.id, s.name from Student s where s.createTime between ? and ?")                .setParameter(0, sdf.parse("2008-01-10 00:00:00"))                .setParameter(1, sdf.parse("2008-02-15 23:59:59"))                      .list();     &lt;/span>  

 

4、Hibernate HQL查詢:直接使用sql進行查詢

Java代碼:

  

Java代碼  收藏代碼
  1. <span style="font-size: medium;">List students = session.createSQLQuery("select * from t_student").list();   </span>  

 
不會返回對象,而是所有屬性!  


5、Hibernate HQL查詢:分頁查詢

* setFirstResult(),從0開始

* setMaxResults,每頁顯示多少條數據

Java代碼:

Java代碼  收藏代碼
  1. <span style="font-size: medium;">List students = session.createQuery("from Student")                .setFirstResult(1)                .setMaxResults(2)                .list();    </span>  

 

6、Hibernate HQL查詢:對象導航查詢,在HQL中採用 . 進行導航

7、Hibernate HQL查詢:連接查詢

* 內連

Sql代碼:  

Java代碼  收藏代碼
  1. <span style="font-size: medium;">SELECT s.name, c.name FROM Student s (inner) join s.classes c    </span>  

 

* 外連接(左連接/右連接)

Sql代碼:

Java代碼  收藏代碼
  1. <span style="font-size: medium;">SELECT s.name, c.name FROM Student s left join s.classes c   </span>  

  

 

 

8、Hibernate HQL查詢:統計查詢

Java代碼:

Java代碼  收藏代碼
  1. <span style="font-size: medium;">List students =session.createQuery("select c.name, count(s) from Student s join s.classes c " +"group by c.name order by c.name").list();      for (Iterator iter=students.iterator(); iter.hasNext();) {           Object[] obj = (Object[])iter.next();           System.out.println(obj[0] + ", " + obj[1]);      }  </span>  

 

9、DML風格的操作(儘量少用,因爲和緩存不同步)

Java代碼:

Java代碼  收藏代碼
  1. <span style="font-size: medium;">session.createQuery  ("update Student s set s.name=? where s.id < ?")                           .setParameter(0"李四")                           .setParameter(15)                           .executeUpdate();    </span>  

 

應當儘量少用,因爲和緩存不同步,也就是說,假如在執行上面的語句之前,已經把student封裝成一個list曾經拿了出來,再執行上面的語句對 student中的表進行數據更新,然後再list Student表,則此時的list是從緩存中取的數據,而不是從表中找到的數據,也就是說,list拿到的是update前的數據,所以造成了這種不同步,所以這種風格儘量少用。

從這個方面也可以看得出Hibernate並不適用於聚集性,統計,大量批量的更新,刪除等操作。

 

第三,本地SQL查詢

使用SQLQuery
對原生SQL查詢執行的控制是通過SQLQuery接口進行的,通過執行Session.createSQLQuery()獲取這個接口。最簡單的情況下,我們可以採用以下形式:

Java代碼  收藏代碼
  1. <span style="font-size: medium;">List cats  =  sess.createSQLQuery( " select * from cats " ).addEntity(Cat. class ).list(); </span>  

 

這個查詢指定了:

SQL查詢字符串

查詢返回的實體

這裏,結果集字段名被假設爲與映射文件中指明的字段名相同。對於連接了多個表的查詢,這就可能造成問題,因爲可能在多個表中出現同樣名字的字段。下面的方法就可以避免字段名重複的問題:

Java代碼  收藏代碼
  1. <span style="font-size: medium;">List cats  =  sess.createSQLQuery( " select {cat.*} from cats cat " ).addEntity( " cat " , Cat. class ).list(); </span>  

 

這個查詢指定了:

SQL查詢語句,它帶一個佔位符,可以讓Hibernate使用字段的別名.

查詢返回的實體,和它的SQL表的別名.

addEntity()方法將SQL表的別名和實體類聯繫起來,並且確定查詢結果集的形態。

addJoin()方法可以被用於載入其他的實體和集合的關聯.

Java代碼  收藏代碼
  1. <span style="font-size: medium;">List cats  =  sess.createSQLQuery(  
  2. " select {cat.*}, {kitten.*} from cats cat, cats kitten where kitten.mother = cat.id " )  
  3. .addEntity( " cat " , Cat. class )  
  4. .addJoin( " kitten " ,  " cat.kittens " )  
  5. .list(); </span>  

 

原生的SQL查詢可能返回一個簡單的標量值或者一個標量和實體的結合體。

Java代碼  收藏代碼
  1. <span style="font-size: medium;">Double max  =  (Double) sess.createSQLQuery( " select max(cat.weight) as maxWeight from cats cat " )  
  2. .addScalar( " maxWeight " , Hibernate.DOUBLE);  
  3. .uniqueResult(); </span>  

  

除此之外,你還可以在你的hbm文件中描述結果集映射信息,在查詢中使用。

Java代碼  收藏代碼
  1. <span style="font-size: medium;">List cats  =  sess.createSQLQuery(  
  2. " select {cat.*}, {kitten.*} from cats cat, cats kitten where kitten.mother = cat.id " )  
  3. .setResultSetMapping( " catAndKitten " )  
  4. .list(); </span>  

 

命名SQL查詢
可以在映射文檔中定義查詢的名字,然後就可以象調用一個命名的HQL查詢一樣直接調用命名SQL查詢.在這種情況下,我們不 需要調用addEntity()方法.

Java代碼  收藏代碼
  1. <span style="font-size: medium;">< sql - query name = " persons " >   
  2.   < return  alias = " person "   class = " eg.Person " />   
  3.  Select person.NAME AS {person.name},person.AGE AS {person.age},person.SEX AS {person.sex} FROM PERSON person Where person.NAME LIKE :namePattern  
  4. </ sql - query > </span>  

 

 

Java代碼  收藏代碼
  1. <span style="font-size: medium;">List people  =  sess.getNamedQuery( " persons " ).setString( " namePattern " , namePattern)  
  2. .setMaxResults( 50 )  
  3. .list(); </span> 
發佈了7 篇原創文章 · 獲贊 6 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章