淺談DetachedCriteria和Criteria的使用方法(必看)
在常規(guī)的Web編程中,有大量的動(dòng)態(tài)條件查詢,即用戶在網(wǎng)頁(yè)上面自由選擇某些條件,程序根據(jù)用戶的選擇條件,動(dòng)態(tài)生成SQL語(yǔ)句,進(jìn)行查詢。
比如,我記得在Facebook中可以選擇高級(jí)查詢條件,這個(gè)就是個(gè)動(dòng)態(tài)的查詢了塞,我們無(wú)法預(yù)知使用多少個(gè)查詢,直接書寫死了在我們的Dao層顯然是不服和我們的意思的塞
針對(duì)這種需求,對(duì)于分層應(yīng)用程序來(lái)說(shuō),Web層需要傳遞一個(gè)查詢的條件列表給業(yè)務(wù)層對(duì)象,業(yè)務(wù)層對(duì)象獲得這個(gè)條件列表之后,然后依次取出條件,構(gòu)造查詢語(yǔ)句。這里的一個(gè)難點(diǎn)是條件列表用什么來(lái)構(gòu)造?傳統(tǒng)上使用Map,但是這種方式缺陷很大,Map可以傳遞的信息非常有限,只能傳遞name和value,無(wú)法傳遞究竟要做怎樣的條件運(yùn)算,究竟是大于,小于,like,還是其它的什么,業(yè)務(wù)層對(duì)象必須確切掌握每條entry的隱含條件。因此一旦隱含條件改變,業(yè)務(wù)層對(duì)象的查詢構(gòu)造算法必須相應(yīng)修改,但是這種查詢條件的改變是隱式約定的,而不是程序代碼約束的,因此非常容易出錯(cuò)。
DetachedCriteria可以解決這個(gè)問(wèn)題,即在web層,程序員使用DetachedCriteria來(lái)構(gòu)造查詢條件,然后將這個(gè) DetachedCriteria作為方法調(diào)用參數(shù)傳遞給業(yè)務(wù)層對(duì)象。而業(yè)務(wù)層對(duì)象獲得DetachedCriteria之后,可以在session范圍內(nèi)直接構(gòu)造Criteria,進(jìn)行查詢。就此,查詢語(yǔ)句的構(gòu)造完全被搬離到web層實(shí)現(xiàn),而業(yè)務(wù)層則只負(fù)責(zé)完成持久化和查詢的封裝即可,與查詢條件構(gòu)造完全解耦,非常完美!
Criteria 和 DetachedCriteria 的主要區(qū)別
在于創(chuàng)建的形式不一樣, Criteria 是在線的,所以它是由 Hibernate Session 進(jìn)行創(chuàng)建的,而 DetachedCriteria 是離線的,創(chuàng)建時(shí)無(wú)需Session .
DetachedCriteria的創(chuàng)建
DetachedCriteria 提供了 2 個(gè)靜態(tài)方法 ,進(jìn)行DetachedCriteria 實(shí)例的創(chuàng)建。
forClass(Class)
forEntityName(Name)
Spring 的框架提供了對(duì)于離線查詢的支持,非常的簡(jiǎn)單的使用那些方法
Spring 的框架提供了getHibernateTemplate().findByCriteria(detachedCriteria) 方法可以很方便地根據(jù)DetachedCriteria 來(lái)返回查詢結(jié)果。Criteria的子類就是 DetachedCriteria 我們可以簡(jiǎn)單的使用就好了。
使用到了這些我們就不得不說(shuō) Restrictions
是產(chǎn)生查詢條件的工具類。Restrictions表達(dá)式如下
HQL運(yùn)算符 QBC運(yùn)算符 含義
= Restrictions.eq() 等于equal
<> Restrictions.ne() 不等于 not equal
Restrictions.gt() 大于greater than = Restrictions.ge() 大于等于 greater than or equal < Restrictions.lt() 小于less than <= Restrictions.le() 小 于 等 于 less than or equal is null Restrictions.isnull() 等于空值 is not null Restrictions.isNotNull() 非空值 like Restrictions.like() 字符串模式匹配 and Restrictions.and() 邏輯與 and Restrictions.conjunction() 邏輯與 or Restrictions.or() 邏輯或 or Restrictions.disjunction() 邏輯或 not Restrictions.not() 邏輯非 in(列表) Restrictions.in() 等于列表中的某一個(gè)值 not in(列表) Restrictions.not(Restrictions.in()) 不等于列表中任意一個(gè)值 between x and y Restrictions.between() 閉區(qū)間 xy中的任意值 not between x and y Restrictions.not(Restrictions..between()) 小于值X 或者大于值y
Criteria 這個(gè)也是必須說(shuō)的東西嘛,翻譯過(guò)來(lái)就是條件,標(biāo)準(zhǔn)之類的意思!和我們的離線的差不都
那么我們看看例子吧
查User表格中的所有資料
我們這個(gè)需要獲取到我們的session對(duì)象哦~~線上的查詢,和我們的Query類似的,但是更強(qiáng)大哦!
Criteria criteria = session.createCriteria(User.class);
List users = criteria.list();
Iterator iterator = users.iterator();
while(iterator.hasNext()) {
User user = (User) iterator.next();
System.out.println(user.getId() + user.getName());
}
Criteria只是個(gè)容器,如果想要設(shè)定查詢條件,只要使用add()方法加入Restrictions的條件限制,例如查詢age大大于20且小于40的資料。雖然我們的SQL語(yǔ)句也是可以完成的,但是為了更好的封裝,更多的復(fù)用代碼,最好還是不要直接的書寫我們的SQL語(yǔ)句,看到了公司封裝的代碼,才感覺(jué)到前輩的強(qiáng)大無(wú)比,復(fù)用代碼的靈活性非常的高! 這里,我們可以傳遞無(wú)限制的Restrictions進(jìn)行封裝起來(lái),非常方便的使用!
Criteria criteria = session.createCriteria(User.class);
criteria.add(Restrictions.gt("age", new Integer(20)));
criteria.add(Restrictions.lt("age", new Integer(40)));
List users = criteria.list();
您也可以使用邏輯組合來(lái)進(jìn)行查詢,例如結(jié)合age等于(eq)20或(or)age為空(isNull)的條件:
一個(gè)單獨(dú)的查詢條件是org.hibernate.criterion.Criterion 接口的一個(gè)實(shí)例。
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();
動(dòng)態(tài)關(guān)聯(lián)抓取
我們的抓取模式,對(duì)于1對(duì)多的關(guān)聯(lián)的形式!是不是抓取過(guò)來(lái)呢?
你可以使用setFetchMode()在運(yùn)行時(shí)定義動(dòng)態(tài)關(guān)聯(lián)抓取的語(yǔ)義
List cats = sess.createCriteria(Cat.class)
.add( Restrictions.like("name", "Fritz%") )
.setFetchMode("mate", FetchMode.EAGER)
.setFetchMode("kittens", FetchMode.EAGER)
.list();
這個(gè)查詢可以通過(guò)外連接抓取mate和kittens。
DetachedCriteria的關(guān)聯(lián)查詢
假設(shè)要通過(guò)stuName查詢一個(gè)學(xué)生Student記錄,可以如下:
DetachedCriteria dc = DetachedCriteria.forClass(Student.class);
dc.add(Restrictions.like("stuName", stuName, MatchMode.ANYWHERE));
如果要通過(guò)Student的Team的teamName查詢一個(gè)Student記錄,很多人都會(huì)這么寫:
DetachedCriteria dc = DetachedCriteria.forClass(Student.class);
dc.add(Restrictions.like("team.teamName", teamName, MatchMode.ANYWHERE));
遺憾的是上述程序報(bào)錯(cuò),說(shuō)是在Student中找不到team.teamName屬性,這是可以理解的。那么如何通過(guò)teamName查找、、Student呢?
可以這么寫:
DetachedCriteria dc = DetachedCriteria.forClass(Student.class);
dc.createAlias("team", "t");
dc.add(Restrictions.like("t.teamName", teamName, MatchMode.ANYWHERE));
沒(méi)錯(cuò),就是要先建立team的引用,才能用team導(dǎo)航到teamName
Department和Employee是一對(duì)多關(guān)聯(lián),查詢條件為: 名稱是“department”開(kāi)發(fā)部門,部門里面的雇員年齡大于20歲;
DetachedCriteria detachedCriteria = DetachedCriteria.forClass(Department.class);
detachedCriteria.add(Restrictions.eq("name", "department"))
.createAlias("employees", "e")
.add(Restrictions.gt(("e.age"), new Integer(20)));
List list = this.getHibernateTemplate().findByCriteria(detachedCriteria);
投影(Projections)、聚合(aggregation)和分組(grouping)
org.hibernate.criterion.Projections是 Projection 的實(shí)例工廠。
我們通過(guò)調(diào)用setProjection()應(yīng)用投影到一個(gè)查詢。這個(gè)的意思就是查詢哪一列的意思
用來(lái)進(jìn)行聚合操作,和sql中的聚合類似.求和/求平均值/統(tǒng)計(jì)記錄數(shù)/…等等.
還有用來(lái)獲取獲取對(duì)象的某些屬性(表字段)或?qū)傩约?正常情況下,查詢返回的是對(duì)象或?qū)ο蟮募?使用投影的話就可以只返回你需要的屬性值.即Hibernate不把記錄封裝對(duì)象了,只返回你在投影中設(shè)置的屬性的值(值的集合)的數(shù)組
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();
在一個(gè)條件查詢中沒(méi)有必要顯式的使用 “group by” 。某些投影類型就是被定義為 分組投影,他們也出現(xiàn)在SQL的group by子句中。
可以選擇把一個(gè)別名指派給一個(gè)投影,這樣可以使投影值被約束或排序所引用。下面是兩種不同的
實(shí)現(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()方法簡(jiǎn)便的將一個(gè)投影實(shí)例包裝到另外一個(gè) 別名的Projection實(shí)例中。簡(jiǎn)而言之, 當(dāng)你添加一個(gè)投影到一個(gè)投影列表中時(shí) 你可以為它指定一個(gè)別名:
List results = session.createCriteria(Cat.class)
.setProjection( Projections.projectionList()//一個(gè)查詢只能使用一個(gè)投影!這里只能這樣處理啦!
.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();
也可以使用Property.forName()來(lái)表示投影:
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();
DetachedCriteria類使你在一個(gè)session范圍之外創(chuàng)建一個(gè)查詢,并且可以使用任意的 Session來(lái)執(zhí)行它。
也可以使用spring封裝好的哦!
DetachedCriteria query = DetachedCriteria.forClass(Cat.class)
.add( Property.forName("sex").eq('F') );
//創(chuàng)建一個(gè)Session
Session session = .;
Transaction txn = session.beginTransaction();
List results = query.getExecutableCriteria(session).setMaxResults(100).list();
txn.commit();
session.close();
也可以是作為子查詢
DetachedCriteria avgWeight = DetachedCriteria.forClass(Cat.class)
.setProjection( Property.forName("weight").avg() );
session.createCriteria(Cat.class)
.add( Property.forName("weight).gt(avgWeight) )
.list();
以上這篇淺談DetachedCriteria和Criteria的使用方法(必看)就是小編分享給大家的全部?jī)?nèi)容了,希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
詳解Java時(shí)區(qū)處理之Date,Calendar,TimeZone,SimpleDateFormat
這篇文章主要介紹了Java時(shí)區(qū)處理之Date,Calendar,TimeZone,SimpleDateFormat的區(qū)別于用法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-07-07
Java數(shù)據(jù)結(jié)構(gòu) 遞歸之迷宮回溯案例講解
這篇文章主要介紹了Java數(shù)據(jù)結(jié)構(gòu)遞歸之迷宮回溯案例講解,本篇文章通過(guò)簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-08-08
解決報(bào)錯(cuò):java.lang.IllegalStateException: Failed to&nb
在項(xiàng)目開(kāi)發(fā)中,可能會(huì)遇到Elasticsearch啟動(dòng)報(bào)錯(cuò)的問(wèn)題,原因可能包括版本不一致、端口配置錯(cuò)誤、配置文件不匹配及服務(wù)未啟動(dòng)等,解決方法包括檢查進(jìn)程、重啟服務(wù)等,這些經(jīng)驗(yàn)可以幫助開(kāi)發(fā)者快速定位問(wèn)題并解決,保證項(xiàng)目順利運(yùn)行2024-10-10
Java的線程池ThreadPoolExecutor及多種線程池實(shí)現(xiàn)詳解
這篇文章主要介紹了Java的線程池ThreadPoolExecutor及多種線程池實(shí)現(xiàn)詳解,ThreadPoolExecutor 使用 int 的高 3 位來(lái)表示線程池狀態(tài),低 29 位表示線程數(shù)量,之所以將信息存儲(chǔ)在一個(gè)變量中,是為了保證原子性,需要的朋友可以參考下2024-01-01
mybatis-plus mapper中foreach循環(huán)操作代碼詳解(新增或修改)
這篇文章主要介紹了mybatis-plus mapper中foreach循環(huán)操作代碼詳解(新增或修改),本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-11-11
Maven搭建springboot項(xiàng)目的方法步驟
這篇文章主要介紹了Maven搭建springboot項(xiàng)目的方法步驟,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-04-04
SpringBoot2.2.X用Freemarker出現(xiàn)404的解決
這篇文章主要介紹了SpringBoot2.2.X用Freemarker出現(xiàn)404的解決,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-02-02

