(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集合是?沒有被條件預過濾的。如果你希望只獲得符合條件的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增删查改+批量
