(3) Hibernate的查询 标准(Criteria)查询
Hibernate的查詢 標準(Criteria)查詢
1 一個簡單例子:
Java代碼??
?@SuppressWarnings("unchecked")
public void searchByPropertys() {
Session session = this.getSession();
Criteria crit = session.createCriteria(Conft.class);
List<Conft> list = crit.list();
for(Conft c : list){
System.out.println(c.getId());
}
}
標準查詢API最終仍然翻譯為SQL交由數(shù)據(jù)庫處理,返回java.util.List對象
?
怎么增加條件呢?請看如下代碼:
Java代碼??
public void searchByPropertys() {
Session session = this.getSession();
Criteria crit = session.createCriteria(Conft.class);
crit.add(Restrictions.eq("id", 2)); // =
crit.add(Restrictions.ne("id", 2)); // !=
crit.add(Restrictions.lt("id", 2)); // <
crit.add(Restrictions.gt("id", 2)); // >
crit.add(Restrictions.le("id", 2)); // <=
crit.add(Restrictions.ge("id", 2)); // >=
crit.add(Restrictions.in("id", new String[]{"2"})); // in
crit.add(Restrictions.like("id", "%2%")); // like
crit.add(Restrictions.like("id", "2",MatchMode.ANYWHERE)); // %x%
crit.add(Restrictions.like("id", "2",MatchMode.START)); // x%
crit.add(Restrictions.like("id", "2",MatchMode.END)); // %x
crit.add(Restrictions.like("id", "2",MatchMode.EXACT)); // x
List<Conft> list = crit.list();
for(Conft c : list){
System.out.println(c.getId());
}
}?
代碼后面寫出了增加條件的方式和意思。
?
如果有and或者是or的關(guān)系的話,可以使用Conjunction(AND)和Disjunction(OR)!
下面是一個使用示例:
Java代碼??
public void searchByPropertys() {
Session session = this.getSession();
Criteria crit = session.createCriteria(Conft.class);
// 創(chuàng)建條件
Criterion a = Restrictions.gt("id", 2); // >
Criterion b = Restrictions.lt("id", 2); // <
Criterion c = Restrictions.like("id", "2",MatchMode.ANYWHERE);
// and 關(guān)系
Conjunction conjunction = Restrictions.conjunction();
conjunction.add(a);
conjunction.add(b);
// or 關(guān)系
Disjunction disjunction = Restrictions.disjunction();
disjunction.add(conjunction);
disjunction.add(c);
// 增加查詢條件
crit.add(disjunction);
List<Conft> list = crit.list();
for(Conft conft : list){
System.out.println(conft.getId());
}
}?
a和b是AND關(guān)系,而a和b合起來作為條件后和c是OR關(guān)系!
如果看他的SQL的話,是這樣的,有助于理解:
Java代碼??
(where (a>? and b<?) or c like ?)
除此之外還可以使用sqlRestriction方法直接拼接SQL
Java代碼??
?public User getUserById(int pk){
Session session = this.getSession();
Criteria crit = session.createCriteria(User.class);
crit.add(Restrictions.sqlRestriction(" {alias}.id=2 "));
List<User> list = crit.list();
return (User)list.get(0);
}
?
注意{alias}是表的名稱,這個不用修改,Hibernate在生成SQL時會自動替換!
在源碼中可以看到:
Java代碼??
public static Criterion sqlRestriction(String sql, Object values[], Type types[])
{
????return new SQLCriterion(sql, values, types);
}
public static Criterion sqlRestriction(String sql, Object value, Type type)
{
????return new SQLCriterion(sql, new Object[] {
????????value
????}, new Type[] {
????????type
????});
}
public static Criterion sqlRestriction(String sql)
{
????return new SQLCriterion(sql, ArrayHelper.EMPTY_OBJECT_ARRAY, ArrayHelper.EMPTY_TYPE_ARRAY);
}?
也就是說這個方法有三個調(diào)用方式,直接寫SQL,如果你的SQL中有 ? 作為占位符,那么可設(shè)置后面兩個參數(shù),第二個參數(shù)對應(yīng) ? ,第三個是參數(shù)字段的類型!
如果有多個 ? ,那么第二和第三個參數(shù)就要用數(shù)組的形式來傳遞!
?
?
2 ?限制結(jié)果集內(nèi)容
一個單獨的查詢條件是org.hibernate.criterion.Criterion?接口的一個實例。org.hibernate.criterion.Restrictions類?定義了獲得某些內(nèi)置Criterion類型的工廠方法。?
List?cats?=?sess.createCriteria(Cat.class)
???.add(?Restrictions.like("name",?"Fritz%")?)
???.add(?Restrictions.between("weight",?minWeight,?maxWeight)?)
???.list();
約束可以按邏輯分組。?
List?cats?=?sess.createCriteria(Cat.class)
???.add(?Restrictions.like("name",?"Fritz%")?)
???.add(?Restrictions.or(
???????Restrictions.eq(?"age",?new?Integer(0)?),
???????Restrictions.isNull("age")
???)?)
???.list();
List?cats?=?sess.createCriteria(Cat.class)
???.add(?Restrictions.in(?"name",?new?String[]?{?"Fritz",?"Izi",?"Pk"?}?)?)
???.add(?Restrictions.disjunction()
???????.add(?Restrictions.isNull("age")?)
?????.add(?Restrictions.eq("age",?new?Integer(0)?)?)
?????.add(?Restrictions.eq("age",?new?Integer(1)?)?)
?????.add(?Restrictions.eq("age",?new?Integer(2)?)?)
???)?)
???.list();
Hibernate提供了相當多的內(nèi)置criterion類型(Restrictions?子類),?但是尤其有用的是可以允許你直接使用SQL。?
List?cats?=?sess.createCriteria(Cat.class)
???.add(?Restrictions.sqlRestriction("lower({alias}.name)?like?lower(?)",?"Fritz%",?Hibernate.STRING)?)
???.list();
{alias}占位符應(yīng)當被替換為被查詢實體的列別名。?
Property實例是獲得一個條件的另外一種途徑。你可以通過調(diào)用Property.forName()?創(chuàng)建一個Property。?
Property?age?=?Property.forName("age");
List?cats?=?sess.createCriteria(Cat.class)
???.add(?Restrictions.disjunction()
???????.add(?age.isNull()?)
?????.add(?age.eq(?new?Integer(0)?)?)
?????.add(?age.eq(?new?Integer(1)?)?)
?????.add(?age.eq(?new?Integer(2)?)?)
???)?)
???.add(?Property.forName("name").in(?new?String[]?{?"Fritz",?"Izi",?"Pk"?}?)?)
???.list();
3 結(jié)果集排序
你可以使用org.hibernate.criterion.Order來為查詢結(jié)果排序。?
List?cats?=?sess.createCriteria(Cat.class)
???.add(?Restrictions.like("name",?"F%")
???.addOrder(?Order.asc("name")?)
???.addOrder(?Order.desc("age")?)
???.setMaxResults(50)
???.list();
List?cats?=?sess.createCriteria(Cat.class)
???.add(?Property.forName("name").like("F%")?)
???.addOrder(?Property.forName("name").asc()?)
???.addOrder(?Property.forName("age").desc()?)
???.setMaxResults(50)
???.list();
4 關(guān)聯(lián)
你可以使用createCriteria()非常容易的在互相關(guān)聯(lián)的實體間建立?約束。?
List?cats?=?sess.createCriteria(Cat.class)
???.add(?Restrictions.like("name",?"F%")?)
???.createCriteria("kittens")
???????.add(?Restrictions.like("name",?"F%")?)
???.list();
注意第二個?createCriteria()返回一個新的?Criteria實例,該實例引用kittens?集合中的元素。?
接下來,替換形態(tài)在某些情況下也是很有用的。?
List?cats?=?sess.createCriteria(Cat.class)
???.createAlias("kittens",?"kt")
???.createAlias("mate",?"mt")
???.add(?Restrictions.eqProperty("kt.name",?"mt.name")?)
???.list();
(createAlias()并不創(chuàng)建一個新的?Criteria實例。)?
Cat實例所保存的之前兩次查詢所返回的kittens集合是?沒有被條件預(yù)過濾的。如果你希望只獲得符合條件的kittens,?你必須使用ResultTransformer。?
List?cats?=?sess.createCriteria(Cat.class)
???.createCriteria("kittens",?"kt")
???????.add(?Restrictions.eq("name",?"F%")?)
???.setResultTransformer(Criteria.ALIAS_TO_ENTITY_MAP)
???.list();
Iterator?iter?=?cats.iterator();
while?(?iter.hasNext()?)?{
???Map?map?=?(Map)?iter.next();
???Cat?cat?=?(Cat)?map.get(Criteria.ROOT_ALIAS);
???Cat?kitten?=?(Cat)?map.get("kt");
}
5 ?動態(tài)關(guān)聯(lián)抓取
你可以使用setFetchMode()在運行時定義動態(tài)關(guān)聯(lián)抓取的語義。?
List?cats?=?sess.createCriteria(Cat.class)
???.add(?Restrictions.like("name",?"Fritz%")?)
???.setFetchMode("mate",?FetchMode.EAGER)
???.setFetchMode("kittens",?FetchMode.EAGER)
???.list();
這個查詢可以通過外連接抓取mate和kittens。?查看第?19.1?節(jié)?“?抓取策略(Fetching?strategies)?”可以獲得更多信息。?
6 查詢示例
org.hibernate.criterion.Example類允許你通過一個給定實例?構(gòu)建一個條件查詢。?
Cat?cat?=?new?Cat();
cat.setSex('F');
cat.setColor(Color.BLACK);
List?results?=?session.createCriteria(Cat.class)
???.add(?Example.create(cat)?)
???.list();
版本屬性、標識符和關(guān)聯(lián)被忽略。默認情況下值為null的屬性將被排除。?
你可以自行調(diào)整Example使之更實用。?
Example?example?=?Example.create(cat)
???.excludeZeroes()???????????//exclude?zero?valued?properties
???.excludeProperty("color")??//exclude?the?property?named?"color"
???.ignoreCase()??????????????//perform?case?insensitive?string?comparisons
???.enableLike();?????????????//use?like?for?string?comparisons
List?results?=?session.createCriteria(Cat.class)
???.add(example)
???.list();
你甚至可以使用examples在關(guān)聯(lián)對象上放置條件。?
List?results?=?session.createCriteria(Cat.class)
???.add(?Example.create(cat)?)
???.createCriteria("mate")
???????.add(?Example.create(?cat.getMate()?)?)
???.list();
7 投影(Projections)、聚合(aggregation)和分組(grouping)
org.hibernate.criterion.Projections是?Projection?的實例工廠。我們通過調(diào)用?setProjection()應(yīng)用投影到一個查詢。?
List?results?=?session.createCriteria(Cat.class)
???.setProjection(?Projections.rowCount()?)
???.add(?Restrictions.eq("color",?Color.BLACK)?)
???.list();
List?results?=?session.createCriteria(Cat.class)
???.setProjection(?Projections.projectionList()
???????.add(?Projections.rowCount()?)
???????.add(?Projections.avg("weight")?)
???????.add(?Projections.max("weight")?)
???????.add(?Projections.groupProperty("color")?)
???)
???.list();
在一個條件查詢中沒有必要顯式的使用?"group?by"?。某些投影類型就是被定義為?分組投影,他們也出現(xiàn)在SQL的group?by子句中。?
你可以選擇把一個別名指派給一個投影,這樣可以使投影值被約束或排序所引用。下面是兩種不同的實現(xiàn)方式:?
List?results?=?session.createCriteria(Cat.class)
???.setProjection(?Projections.alias(?Projections.groupProperty("color"),?"colr"?)?)
???.addOrder(?Order.asc("colr")?)
???.list();
List?results?=?session.createCriteria(Cat.class)
???.setProjection(?Projections.groupProperty("color").as("colr")?)
???.addOrder(?Order.asc("colr")?)
???.list();
alias()和as()方法簡便的將一個投影實例包裝到另外一個?別名的Projection實例中。簡而言之,當你添加一個投影到一個投影列表中時?你可以為它指定一個別名:?
List?results?=?session.createCriteria(Cat.class)
???.setProjection(?Projections.projectionList()
???????.add(?Projections.rowCount(),?"catCountByColor"?)
???????.add(?Projections.avg("weight"),?"avgWeight"?)
???????.add(?Projections.max("weight"),?"maxWeight"?)
???????.add(?Projections.groupProperty("color"),?"color"?)
???)
???.addOrder(?Order.desc("catCountByColor")?)
???.addOrder(?Order.desc("avgWeight")?)
???.list();
List?results?=?session.createCriteria(Domestic.class,?"cat")
???.createAlias("kittens",?"kit")
???.setProjection(?Projections.projectionList()
???????.add(?Projections.property("cat.name"),?"catName"?)
???????.add(?Projections.property("kit.name"),?"kitName"?)
???)
???.addOrder(?Order.asc("catName")?)
???.addOrder(?Order.asc("kitName")?)
???.list();
你也可以使用Property.forName()來表示投影:?
List?results?=?session.createCriteria(Cat.class)
???.setProjection(?Property.forName("name")?)
???.add(?Property.forName("color").eq(Color.BLACK)?)
???.list();
List?results?=?session.createCriteria(Cat.class)
???.setProjection(?Projections.projectionList()
???????.add(?Projections.rowCount().as("catCountByColor")?)
???????.add(?Property.forName("weight").avg().as("avgWeight")?)
???????.add(?Property.forName("weight").max().as("maxWeight")?)
???????.add(?Property.forName("color").group().as("color"?)
???)
???.addOrder(?Order.desc("catCountByColor")?)
???.addOrder(?Order.desc("avgWeight")?)
???.list();
8 離線(detached)查詢和子查詢
DetachedCriteria類使你在一個session范圍之外創(chuàng)建一個查詢,并且可以使用任意的?Session來執(zhí)行它。?
DetachedCriteria?query?=?DetachedCriteria.forClass(Cat.class)
???.add(?Property.forName("sex").eq('F')?);
???
Session?session?=?....;
Transaction?txn?=?session.beginTransaction();
List?results?=?query.getExecutableCriteria(session).setMaxResults(100).list();
txn.commit();
session.close();
DetachedCriteria也可以用以表示子查詢。條件實例包含子查詢可以通過?Subqueries或者Property獲得。?
DetachedCriteria?avgWeight?=?DetachedCriteria.forClass(Cat.class)
??.setProjection(?Property.forName("weight").avg()?);
session.createCriteria(Cat.class)
??.add(?Property.forName("weight).gt(avgWeight)?)
??.list();
DetachedCriteria?weights?=?DetachedCriteria.forClass(Cat.class)
??.setProjection(?Property.forName("weight")?);
session.createCriteria(Cat.class)
??.add(?Subqueries.geAll("weight",?weights)?)
??.list();
甚至相互關(guān)聯(lián)的子查詢也是有可能的:?
DetachedCriteria?avgWeightForSex?=?DetachedCriteria.forClass(Cat.class,?"cat2")
??.setProjection(?Property.forName("weight").avg()?)
??.add(?Property.forName("cat2.sex").eqProperty("cat.sex")?);
session.createCriteria(Cat.class,?"cat")
??.add(?Property.forName("weight).gt(avgWeightForSex)?)
??.list();
9 根據(jù)自然標識查詢(Queries?by?natural?identifier)
對大多數(shù)查詢,包括條件查詢而言,因為查詢緩存的失效(invalidation)發(fā)生得太頻繁,查詢緩存不是非常高效。然而,有一種特別的查詢,可以通過不變的自然鍵優(yōu)化緩存的失效算法。在某些應(yīng)用中,這種類型的查詢比較常見。條件查詢API對這種用例提供了特別規(guī)約。?
首先,你應(yīng)該對你的entity使用<natural-id>來映射自然鍵,然后打開第二級緩存。?
<class?name="User">
???<cache?usage="read-write"/>
???<id?name="id">
???????<generator?class="increment"/>
???</id>
???<natural-id>
???????<property?name="name"/>
???????<property?name="org"/>
???</natural-id>
???<property?name="password"/>
</class>
注意,此功能對具有mutable自然鍵的entity并不適用。?
然后,打開Hibernate?查詢緩存。?
現(xiàn)在,我們可以用Restrictions.naturalId()來使用更加高效的緩存算法。?
session.createCriteria(User.class)
???.add(?Restrictions.naturalId()
???????.set("name",?"gavin")
???????.set("org",?"hb")?
???).setCacheable(true)
???.uniqueResult();
?
總結(jié)
以上是生活随笔為你收集整理的(3) Hibernate的查询 标准(Criteria)查询的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: (2)hibernate HQL命名查询
- 下一篇: (4) hibernate增删查改+批量