Hibernate查詢快速入門
如果不知道所要尋找的對(duì)象的持久化標(biāo)識(shí),那么你需要使用Hibernate查詢。在這里拿出來和大家分享一下我的經(jīng)驗(yàn),希望對(duì)大家有用。
Hibernate支持強(qiáng)大且易于使用的面向?qū)ο蟛樵冋Z言(HQL)。 如果希望通過編程的方式創(chuàng)建查詢,Hibernate提供了完善的按條件(Query By Criteria, QBC)以及按樣例(Query By Example, QBE)進(jìn)行Hibernate查詢的功能。 你也可以用原生SQL(native SQL)描述Hibernate查詢,Hibernate額外提供了將結(jié)果集(result set)轉(zhuǎn)化為對(duì)象的支持。
執(zhí)行查詢
HQL和原生SQL(native SQL)查詢要通過為org.hibernate.Query的實(shí)例來表達(dá)。 這個(gè)接口提供了參數(shù)綁定、結(jié)果集處理以及運(yùn)行實(shí)際查詢的方法。 你總是可以通過當(dāng)前Session獲取一個(gè)Query對(duì)象:
- 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());
一個(gè)查詢通常在調(diào)用list()時(shí)被執(zhí)行,執(zhí)行結(jié)果會(huì)完全裝載進(jìn)內(nèi)存中的一個(gè)集合(collection)。 查詢返回的對(duì)象處于持久(persistent)狀態(tài)。如果你知道的查詢只會(huì)返回一個(gè)對(duì)象,可使用list()的快捷方式uniqueResult()。 注意,使用集合預(yù)先抓取的查詢往往會(huì)返回多次根對(duì)象(他們的集合類都被初始化了)。你可以通過一個(gè)集合來過濾這些重復(fù)對(duì)象。
某些情況下,你可以使用iterate()
方法得到更好的性能。 這通常是你預(yù)期返回的結(jié)果在session,或二級(jí)緩存(second-level cache)中已經(jīng)存在時(shí)的情況。 如若不然,iterate()
會(huì)比list()
慢,而且可能簡(jiǎn)單查詢也需要進(jìn)行多次數(shù)據(jù)庫訪問: iterate()
會(huì)首先使用1條語句得到所有對(duì)象的持久化標(biāo)識(shí)(identifiers),再根據(jù)持久化標(biāo)識(shí)執(zhí)行n條附加的select語句實(shí)例化實(shí)際的對(duì)象。
- // 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)指一條結(jié)果行包含多個(gè)對(duì)象) Hibernate查詢有時(shí)返回元組(tuples),每個(gè)元組(tuples)以數(shù)組的形式返回:
- 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. 標(biāo)量(Scalar)結(jié)果
查詢可在select從句中指定類的屬性,甚至可以調(diào)用SQL統(tǒng)計(jì)(aggregate)函數(shù)。 屬性或統(tǒng)計(jì)結(jié)果被認(rèn)定為"標(biāo)量(Scalar)"的結(jié)果(而不是持久(persistent state)的實(shí)體)。
- 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. 綁定參數(shù)
接口Query提供了對(duì)命名參數(shù)(named parameters)、JDBC風(fēng)格的問號(hào)(?)參數(shù)進(jìn)行綁定的方法。 不同于JDBC,Hibernate對(duì)參數(shù)從0開始計(jì)數(shù)。 命名參數(shù)(named parameters)在查詢字符串中是形如:name的標(biāo)識(shí)符。 命名參數(shù)(named parameters)的優(yōu)點(diǎn)是:
命名參數(shù)(named parameters)與其在查詢串中出現(xiàn)的順序無關(guān)
它們可在同一查詢串中多次出現(xiàn)
它們本身是自我說明的
- //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. 分頁
如果你需要指定結(jié)果集的范圍(希望返回的***行數(shù)/或開始的行數(shù)),應(yīng)該使用Query接口提供的方法:
- Query q = sess.createQuery("from DomesticCat cat");
- q.setFirstResult(20);
- q.setMaxResults(10);
- List cats = q.list();
Hibernate 知道如何將這個(gè)有限定條件的查詢轉(zhuǎn)換成你的數(shù)據(jù)庫的原生SQL(native SQL)。
6. 可滾動(dòng)遍歷(Scrollable iteration)
如果你的JDBC驅(qū)動(dòng)支持可滾動(dòng)的ResuleSet,Query接口可以使用ScrollableResults,允許你在查詢結(jié)果中靈活游走。
- 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()
請(qǐng)注意,使用此功能需要保持?jǐn)?shù)據(jù)庫連接(以及游標(biāo)(cursor))處于一直打開狀態(tài)。 如果你需要斷開連接使用分頁功能,請(qǐng)使用setMaxResult()/setFirstResult()
7. 外置命名查詢(Externalizing named queries)
你可以在映射文件中定義命名查詢(named queries)。 (如果你的查詢串中包含可能被解釋為XML標(biāo)記(markup)的字符,別忘了用CDATA包裹起來。)
參數(shù)綁定及執(zhí)行以編程方式(programatically)完成:
- Query q = sess.getNamedQuery("ByNameAndMaximumWeight");
- q.setString(0, name);
- q.setInt(1, minWeight);
- List cats = q.list();
請(qǐng)注意實(shí)際的程序代碼與所用的查詢語言無關(guān),你也可在元數(shù)據(jù)中定義原生SQL(native SQL)查詢, 或?qū)⒃械钠渌牟樵冋Z句放在配置文件中,這樣就可以讓Hibernate統(tǒng)一管理,達(dá)到遷移的目的。
也請(qǐng)注意在
【編輯推薦】