Hibernate查詢快速入門
如果不知道所要尋找的對象的持久化標識,那么你需要使用Hibernate查詢。在這里拿出來和大家分享一下我的經驗,希望對大家有用。
Hibernate支持強大且易于使用的面向對象查詢語言(HQL)。 如果希望通過編程的方式創建查詢,Hibernate提供了完善的按條件(Query By Criteria, QBC)以及按樣例(Query By Example, QBE)進行Hibernate查詢的功能。 你也可以用原生SQL(native SQL)描述Hibernate查詢,Hibernate額外提供了將結果集(result set)轉化為對象的支持。
執行查詢
HQL和原生SQL(native SQL)查詢要通過為org.hibernate.Query的實例來表達。 這個接口提供了參數綁定、結果集處理以及運行實際查詢的方法。 你總是可以通過當前Session獲取一個Query對象:
- List cats = session.createQuery(
- "from Cat as cat where cat.birthdate < ?")
- .setDate(0, date)
- .list();
- List mothers = session.createQuery(
- "select mother from Cat as cat join cat.mother as mother where cat.name = ?")
- .setString(0, name)
- .list();
- List kittens = session.createQuery(
- "from Cat as cat where cat.mother = ?")
- .setEntity(0, pk)
- .list();
- Cat mother = (Cat) session.createQuery(
- "select cat.mother from Cat as cat where cat = ?")
- .setEntity(0, izi)
- .uniqueResult();]]
- Query mothersWithKittens = (Cat) session.createQuery(
- "select mother from Cat as mother left join fetch mother.kittens");
- Set uniqueMothers = new HashSet(mothersWithKittens.list());
一個查詢通常在調用list()時被執行,執行結果會完全裝載進內存中的一個集合(collection)。 查詢返回的對象處于持久(persistent)狀態。如果你知道的查詢只會返回一個對象,可使用list()的快捷方式uniqueResult()。 注意,使用集合預先抓取的查詢往往會返回多次根對象(他們的集合類都被初始化了)。你可以通過一個集合來過濾這些重復對象。
某些情況下,你可以使用iterate()
方法得到更好的性能。 這通常是你預期返回的結果在session,或二級緩存(second-level cache)中已經存在時的情況。 如若不然,iterate()
會比list()
慢,而且可能簡單查詢也需要進行多次數據庫訪問: iterate()
會首先使用1條語句得到所有對象的持久化標識(identifiers),再根據持久化標識執行n條附加的select語句實例化實際的對象。
- // fetch ids
- Iterator iter = sess.createQuery("from eg.Qux q order by q.likeliness").iterate();
- while ( iter.hasNext() ) {
- Qux qux = (Qux) iter.next(); // fetch the object
- // something we couldnt express in the query
- if ( qux.calculateComplicatedAlgorithm() ) {
- // delete the current instance
- iter.remove();
- // dont need to process the rest
- break;
- }
- }
2. 返回元組(tuples)的查詢
(譯注:元組(tuples)指一條結果行包含多個對象) Hibernate查詢有時返回元組(tuples),每個元組(tuples)以數組的形式返回:
- Iterator kittensAndMothers = sess.createQuery(
- "select kitten, mother from Cat kitten join kitten.mother mother")
- .list()
- .iterator();
- while ( kittensAndMothers.hasNext() ) {
- Object[] tuple = (Object[]) kittensAndMothers.next();
- Cat kitten = tuple[0];
- Cat mother = tuple[1];
- ....
- }
3. 標量(Scalar)結果
查詢可在select從句中指定類的屬性,甚至可以調用SQL統計(aggregate)函數。 屬性或統計結果被認定為"標量(Scalar)"的結果(而不是持久(persistent state)的實體)。
- Iterator results = sess.createQuery(
- "select cat.color, min(cat.birthdate), count(cat) from Cat cat " +
- "group by cat.color")
- .list()
- .iterator();
- while ( results.hasNext() ) {
- Object[] row = (Object[]) results.next();
- Color type = (Color) row[0];
- Date oldest = (Date) row[1];
- Integer count = (Integer) row[2];
- .....
- }
4. 綁定參數
接口Query提供了對命名參數(named parameters)、JDBC風格的問號(?)參數進行綁定的方法。 不同于JDBC,Hibernate對參數從0開始計數。 命名參數(named parameters)在查詢字符串中是形如:name的標識符。 命名參數(named parameters)的優點是:
命名參數(named parameters)與其在查詢串中出現的順序無關
它們可在同一查詢串中多次出現
它們本身是自我說明的
- //named parameter (preferred)
- Query q = sess.createQuery("from DomesticCat cat where cat.name = :name");
- q.setString("name", "Fritz");
- Iterator cats = q.iterate();
- //positional parameter
- Query q = sess.createQuery("from DomesticCat cat where cat.name = ?");
- q.setString(0, "Izi");
- Iterator cats = q.iterate();
- //named parameter list
- List names = new ArrayList();
- names.add("Izi");
- names.add("Fritz");
- Query q = sess.createQuery("from DomesticCat cat where cat.name in (:namesList)");
- q.setParameterList("namesList", names);
- List cats = q.list();
5. 分頁
如果你需要指定結果集的范圍(希望返回的***行數/或開始的行數),應該使用Query接口提供的方法:
- Query q = sess.createQuery("from DomesticCat cat");
- q.setFirstResult(20);
- q.setMaxResults(10);
- List cats = q.list();
Hibernate 知道如何將這個有限定條件的查詢轉換成你的數據庫的原生SQL(native SQL)。
6. 可滾動遍歷(Scrollable iteration)
如果你的JDBC驅動支持可滾動的ResuleSet,Query接口可以使用ScrollableResults,允許你在查詢結果中靈活游走。
- Query q = sess.createQuery("select cat.name, cat from DomesticCat cat " +
- "order by cat.name");
- ScrollableResults cats = q.scroll();
- if ( cats.first() ) {
- // find the first name on each page of an alphabetical list of cats by name
- firstNamesOfPages = new ArrayList();
- do {
- String name = cats.getString(0);
- firstNamesOfPages.add(name);
- }
- while ( cats.scroll(PAGE_SIZE) );
- // Now get the first page of cats
- pageOfCats = new ArrayList();
- cats.beforeFirst();
- int i=0;
- while( ( PAGE_SIZE > i++ ) && cats.next() ) pageOfCats.add( cats.get(1) );
- }
- cats.close()
請注意,使用此功能需要保持數據庫連接(以及游標(cursor))處于一直打開狀態。 如果你需要斷開連接使用分頁功能,請使用setMaxResult()/setFirstResult()
7. 外置命名查詢(Externalizing named queries)
你可以在映射文件中定義命名查詢(named queries)。 (如果你的查詢串中包含可能被解釋為XML標記(markup)的字符,別忘了用CDATA包裹起來。)
參數綁定及執行以編程方式(programatically)完成:
- Query q = sess.getNamedQuery("ByNameAndMaximumWeight");
- q.setString(0, name);
- q.setInt(1, minWeight);
- List cats = q.list();
請注意實際的程序代碼與所用的查詢語言無關,你也可在元數據中定義原生SQL(native SQL)查詢, 或將原有的其他的查詢語句放在配置文件中,這樣就可以讓Hibernate統一管理,達到遷移的目的。
也請注意在
【編輯推薦】