1、背景了解:Hibernate的三種查詢方式
Hibernate總的來說共有三種查詢方式:HQL、QBC和SQL三種,這里做簡單的概念介紹,不詳細進行展開。
1.1 HQL(Hibernate Query Language)
與所熟悉的SQL的語法差不太多,不同的就是把表名換成了類或者對象,如下示例:
public SysUser findUserByLoginName(String pLoginName) {
String hql = "from SysUser as u where u.loginName = ?";
List<SysUser> users = getHibernateTemplate().find(hql, pLoginName); //pLoginName對應?
return users.isEmpty() ? null : users.get(0);
}
1.2 SQL(Structured Query Language)
static List sql() {
Session s = HibernateUtil.getSession();
Query q = s.createSQLQuery("select * from user").addEntity(User.class);
List<User> rs = q.list();
s.close();
return rs;
}
缺點:違背了hibernate的跨平台優點,不易維護,不面向對象。不推薦使用。
1.3 QBC(Query By Criteria)
1.3.1 QBC查詢的基本步驟
這種方式比較面向對象方式,重點是有三個描述條件的對象:Restrictions,Order,Projections。使用QBC查詢,一般需要以下三個步驟:
- 使用Session實例的createCriteria()方法創建Criteria對象;
- 使用工具類Restrictions的方法為Criteria對象設置查詢條件,Order工具類的方法設置排序方式,Projections工具類的方法進行統計和分組;
- 使用Criteria對象的list()方法進行查詢並返回結果。
1.3.2 Restrictions、Order、Projections的常用方法
Restrictions類的常用方法(設置查詢條件):
返回值類型 | 方法名稱 | 描述 |
SimpleExpression | Restrictions.eq | 等於(equal) |
Criterion | Restrictions.allEq | 使用Map,Key/Valu進行多個等於的比對 |
SimpleExpression | Restrictions.gt | 大於(great than) |
SimpleExpression | Restrictions.ge | 大於等於(great than or equal) |
SimpleExpression | Restrictions.lt | 小於(less than) |
SimpleExpression | Restrictions.le | 小於等於(less than or equal) |
Criterion | Restrictions.between | 對應SQL的between |
SimpleExpression | Restrictions.like | 對應SQL的like |
Criterion | Restrictions.in | 對應SQL的in |
LogicalExpression | Restrictions.and | and關系 |
LogicalExpression | Restrictions.or | or關系 |
Criterion | Restrictions.isNull | 為空 |
Criterion | Restrictions.sqlRestriction | SQL限定查詢 |
Order類的常用方法(設置排序方式):
返回值類型 | 方法名稱 | 描述 |
Order | Order.asc | 升序 |
Order | Order.desc | 降序 |
Projections類的常用方法(統計和分組):
返回值類型 | 方法名稱 | 描述 |
AggregateProjection | Projections.avg | 求平均值 |
CountProjection | Projections.count | 統計某屬性的數量 |
CountProjection | Projections.countDistinct | 統計某屬性不同值的數量 |
PropertyProjection | Projections.groupProperty | 指定某個屬性為分組屬性 |
AggregateProjection | Projections.max | 求最大值 |
AggregateProjection | Projections.min | 求最小值 |
ProjectionList | Projections.projectionList | 創建一個ProjectionList對象 |
Projection | Projections.rowCount | 查詢結果集中的記錄條數 |
AggregateProjection | Projections.sum | 求某屬性的合計 |
更多方法,以及方法的詳細使用及解釋,請參看
在線API:Hibernate API Documentation(3.2.7.ga)
1.3.3 QBC的查詢示例和基本理解
接下來,基於以上的一些常用方法,我們先看兩個示例:
//查詢匹配的賬戶adminList
Criteria c=s.createCriteria(Admin.class);
c.add(Restrictions.eq("aname",name));//eq是等於,gt是大於,lt是小於,or是或
c.add(Restrictions.eq("apassword", password));
List<Admin> list=c.list();
//分頁查詢前10條
Criteria criteria = session.createCriteria(Customer.class);
criteria.addOrder( Order.asc("name") ); //排序方式
criteria.setFirstResult(0);
criteria.setMaxResults(10);
List result = criteria.list()
看到這里,流程大概很好理解,從方法名就知道無非是把各種條件往里面加最后就可以獲得一個符合條件的list。那么,
下面再延伸理解一下:
org.hibernate.Criteria實際上是個條件附加的容器,如果想要設定查詢條件,則要使用
org.hibernate.criterion.Restrictions的各種靜態方法傳回org.hibernate.criterion.
Criterion
實例,傳回的每個org.hibernate.criterion.Criteria實例代表着一個條件,你要
使用org.hibernate.Criteria的add()方法加入這些條件實例。下面看個示例:
//查找age等於(eq)20或(or)age為空(isNull)的User
Criteria criteria = session.createCriteria(User.class);
criteria.add(Restrictions.or( Restrictions.eq("age", new Integer(20)), Restrictions.isNull("age") ));
List users = criteria.list();
//實際上它產生的對應的sql如下
Hibernate:
select
this_.id as id0_0_, this_.name as name0_0_, this_.age as age0_0_
from
T_USER this_
where
(this_.age=? or this_.age is null)
1.3.4 復合查詢
復合查詢就是在原有的查詢基礎上在進行查詢,比如有Clazz班級,包含對象屬性Student,那么我們希望查詢 “包含學生姓名為Bob” 的班級,那么就可以使用復合查詢:
Criteria criteria = session.createCriteria(Clazz.class);
Criteria criteriaInner = criteria.createCriteria(Student.class);
criteriaInner.add(Restrictions.eq("name", "Bob"));
List clazzList = criteria.list();
如果是DetachedCriteria,則是根據關聯屬性的名稱,而非Class,如:
Member member = MemberHelper.getCurrentLoginMember();
DetachedCriteria criteria = DetachedCriteria.forClass(Picture.class);
DetachedCriteria collectCriteria = criteria.createCriteria("collectRecordList");
collectCriteria.add(Restrictions.eq("member", member));
List<Picture> pictureList = Picture.listByCriteria(criteria, page, Order.desc("updateDate"));
1.3.5 Hibernate中Criteria方式的基本使用流程
所以,基於以上的的示例和理解,我們不難看出Criteria的基本使用流程:
- Criteria創建 --> session.createCriteria(Class persistentClass) (更多重載參考)
- 條件添加 --> add(Criterion criterion) 限定條件、 addOrder(Order order) 限定順序、 setProjection(Projection projection) 限定統計動作
- 結果返回 --> list()
2、DetachedCriteria是什么,和Criteria有什么區別
父接口CriteriaSpecification,其下有子接口Criteria和實現類DetachedCriteria,
Criteria和DetachedCriteria均可使用Criterion和Projection設置查詢條件。可以設置FetchMode( 聯合查詢抓取的模式 ) ,設置排序方式。對於Criteria還可以設置FlushModel(沖刷 Session 的方式)和LockMode(數據庫鎖模式)。
Criteria和DetachedCriteria的主要區別在於創建的形式不一樣,Criteria是在線的,所以它是由Hibernate Session進行創建的;而
DetachedCriteria是離線的,創建時無需Session,它通過2個靜態方法forClass(Class) 或 forEntityName(Name) 進行DetachedCriteria 的實例創建。
(另,Spring的框架提供了getHibernateTemplate ().findByCriteria(detachedCriteria) 方法可以很方便地根據DetachedCriteria來返回查詢結果)
所以它也稱為離線條件查詢,即建立一個DetachedCriteria對象,將查詢的條件等指定好,然后在session.beginTransaction()后將這個對象傳入。通常這個對象可以在表示層建立,然后傳入業務層進行查詢。
3、DetachedCriteria的基本使用
上面已經提到,Criteria和DetachedCriteria均可使用Criterion和Projection設置查詢條件,設置排序方式。那么這里也無需過度展開,以一個簡單的例子來示意吧:
//查詢id為1且在今天或今天之前出生的user的名單
//1、創建DetachedCriteria並設置條件
DetachedCriteria dc = DetachedCriteria.forClass(User.class);
int id = 1;
dc.add(Restrictions.eq("id", id));
Date age = new Date();
dc.add(Restrictions.le("birthday", age));
//2、執行查詢(Criteria getExecutableCriteria(Session session))
Session session = HibernateUtil.getSession();
Criteria c = dc.getExecutableCriteria(session);
List users = c.list();
這里值得一提的是,DetachedCriteria並沒有像Criteria一樣有list()的方法來返回List,所以需要以此獲取一個可執行的Criteria,達到真正執行查詢的目的,我們看下官方的解釋:
org.hibernate.criterion
Class DetachedCriteria
getExecutableCriteria
public Criteria getExecutableCriteria(Session session)
Get an executable instance of Criteria, to actually run the query.