转载:http://blog.sina.com.cn/s/blog_7fff746d0101ese2.html
本章的主要内容包括:
● QBC数据检索
● 连接查询
● Hibernate的数据检索策略
QBC数据检索
Hibernate提供了另一种形式的面向对象的查询方式QBC(Query by Criteria)。这种查询是以函数API的方式动态地设置查询条件,组成查询语句。基本结构是session创建criteria接口,然后调用criteria接口的add函数,增加查询条件(即criterion类),然后调用criteria的list()函数返回查询结果。
除了有当前session创建的criteria接口外,Hibernate还提供了在session不可用时,组织查询语句的游离态的DetachCriteria类,它的查询条件设置与criteria类似,只是它不由session创建,而是在需要session可用时,再调用getExecutableCriteria()执行查询。
另外,为了让criteria的查询方法与HQL一样功能丰富,Hibernate还提供了projections类,用于提供各种函数来产生可以使用聚集函数,进行投影查询和进行查询结果设置的各种projection接口,提供了Restrictions类用于提供各种函数来产生各种criterion作为查询条件,提供了用于结果排序的order类。
图8-1是Criteria相关类的结构图。
图8-1 Criteria相关类图
由图8-1可见,Criteria接口和DetachedCriteria类都继承了CriteriaSpecification接口,开发人员在使用QBC查询时,都是直接选择用Criteria或DetachedCriteria。而它们两个都是一样使用可以设置各种查询条件或者查询结果的Criterion,Projection等接口。
8.1.1 QBC查询主要类
下面分别对QBC查询中使用的几个主要接口和类进行介绍。
1. Criteria接口
Criteria调用add函数添加Criterion对象来组成查询条件,然后根据查询条件来查询持久化类对象。与HQL查询的Query类一样,也是由Session调用createCriteria()函数创建。
以下代码是检索价格大于25的Product对象。
Criteria crit = session.createCriteria(Product.class);
crit.add(Restrictions.gt("price",new Double(25.0)));
List results = crit.list();
相应地,HQL实现的代码如下:
Query query = session.createQuery(
"from Product where price>:price");
query.setDouble("price",25.0);
List results = query.list();
使用Criteria查询的步骤是:(ke ruai tie ria)
(1) 调用一个可用的session的createCriteria()方法创建Criteria对象,其中createCriteria()方法以被查询的实体类类型作为参数。
(2) 根据需要使用add函数设置各种criterion查询条件,使用setProjection设置projection
(3) 调用Criteria的list或者scroll方法即执行查询语句,检索数据库,把查询结果返回放在List或ScrollableResults中。
(4) 读取List和ScrollableResults,即可取出查询对象。
Criteria接口在调用List或者Scroll方法时执行数据库检索,返回结果可以是以List形式或者ScrollableResults形式,与Query相比,少了iterate()方法执行返回iterator形式的结果。另外,与Query类似,Criteria也可以使用setFlushMode、setCacheMode、setTimeOut等设置各种Criteria查询的环境,可以使用setFirstResult()、setMaxResult()等方法设置检索结果。
下面介绍在Query中没有的,但在Criteria中使用的主要的函数:
(1) Criteria add(Criterion criterion)
用于添加查询条件,相当于设置HQL中的where从句。当有多个查询条件时,可以逐个增加。例如:
Criteria crit = session.createCriteria(Product.class);
crit.add(Restrictions.gt("price",new Double(25.0)));
crit.add(Restrictions.gt("name","Clothes"));
List results = crit.list();
或者使用方法链编程风格:
List results=session.createCriteria(Product.class)
.add(Restrictions.gt("price",new Double(25.0)))
.add(Restrictions.gt("name","Clothes"))
.list();
多个add相当于对查询条件进行and操作,即要求同时满足这些条件。
(2) Criteria addOrder(Order order)
如果需要排序,可以使用Criteria的addOrder()方法增加排序用的Order类。
(3) Criteria createAlias(String associationPath, String alias)
Criteria createAlias(String associationPath, String alias, int joinType)
List cats = sess.createCriteria(Cat.class) .createAlias("kittens", "kt") .createAlias("mate", "mt") .add( Restrictions.eqProperty("kt.name", "mt.name") ) .list();
用于设置连接查询,第一种重载形式使用的是默认的内连接;第二种重载形式可以选择连接方式。
associationPath:属性的路径,使用点“.”作为分割符。例如,Basiccar持久化类中有集合属性persons,而persons中的元素是持久化类Person,而Person类中有集合属性clotheses,其中存有关联对象clothes,如果要从Basiccar对象关联到clothes对象,属性路径就写成:persons.clotheses,使用点隔开。
alias:关联属性的别名,后面可以使用这个别名来设置关联条件。
joinType:连接查询时选择的关联方式。joinType可以是内连接CriteriaSpecification.INNER_JOIN(默认值)、全连接CriteriaSpecification.FULL_JOIN, 或者左连接CriteriaSpecification.LEFT_JOIN。
(4) Criteria createCriteria(String associationPath)
Criteria createCriteria(String associationPath, int joinType)
Criteria createCriteria(String associationPath, String alias)
Criteria createCriteria(String associationPath, String alias, int joinType)
创建一个指向主类关联的实体的criteria查询,在进行存在关联关系的对象检索时会用到。
joinType可以指定关联是内连接、左联接还是全连接。alias则可以指定别名。
返回值是被创建的子查询。
(5) Criteria setProjection(Projection projection)
如果需要使用投影查询、聚集函数等,可以按需要生成Projection类,然后使用Criteria的setProjection()方法,对返回结果进行某些列的投影或聚集运算。
2. DetachedCriteria类
使用Criteria查询需要当前有可用的session,但是,有时构造查询语句时,并不一定能得到可用的session。例如,在分层的项目开发过程中,通常会在表现层,根据用户选择的条件,动态生成SQL语句,进行查询。这个时候,表现层是得不到session的,但是它需要把构造好的查询传给业务层进行session查询。DetachedCriteria就可以解决这个问题,即在表现层,应用程序使用DetachedCriteria来构造查询条件,然后把这个detachedCriteria传递给业务层对象,让业务层在session范围内构造criteria查询。所以,detachedCriteria在构造查询时,session还不可用,detachedCriteria查询面对的是游离的POJO类,而Criteria查询时面对的持久化对象,所以称为detachedCriteria。以下是一个使用DetachedCriteria查询的简单例子。
DetachedCriteria detachedCriteria= DetachedCriteria.forClass (BasicCar.class); detachedCriteria.add(Restrictions.eq("id", new Integer(1)));
上面的代码片段先创建了一个DetachedCriteria的实例,然后只要在有可用的session时,使用它的getExecutableCriteria()方法,把这个可用的session关联进来即可,它会返回一个在这个session内进行查询的criteria类。代码如下所示:
Criteria crit=detachedCriteria.getExecutableCriteria(session);
List results = crit.list();
DetachedCriteria 提供了4个静态方法forClass(Class)或forEntityName(Name)进行DetachedCriteria实例的创建。DetachedCriteria也提供了add(Criterion)、addOrder(Order)、setProjection(Projection)、createAlias()、createCriteria()等方法用于构造查询及其返回结果,与Criteria提供的函数不同的是,DetachedCriteria类提供的函数返回也是DetachedCriteria 类。
3. Criterion和Retrictions类
Criterion被Criteria接口的add()方法调用,作为查询条件。内置的Criterion类型由Restrictions这个工厂类提供。实现Criterion接口的可以用来作为查询条件的类包括Expression、Example、Junction等。
Criterion的类图关系如图8-2所示。
图8-2 Criterion相关类图
4. Projection和Projections
Projection接口是Criteria查询结果集的投影表示。内置的Projection类由Projections工厂类提供。实现projection接口的类包括AliasedProjection、Distinct、ProjectionList、SimpleProjection、SQLProjection等5个。Projection的类图如图8-3所示。
图8-3 Projection相关类图
Projection接口被作为Criteria的setProjection()函数的参数,对查询结果进行选择某些属性的投影,进行avg、max、min、count、sum等聚集运算。
Projections提供多种静态方法来产生对查询的结果进行各种运算的projection实例。
表8-1列出了Projections提供的各种结果运算的函数,以及相应的HQL运算符。
表8-1 Projections的函数
意 思
Projections函数(重点)
HQL例子
1、计算平均值
avg(String?propertyName)
Select avg(o.property) from Object o
2、计算数目
count(String?propertyName)
Select count(o.property) from Object o
3、过滤相同值的属性然后计算数目
countDistinct(String?propertyName)
Select count(distinct o.property) from Object o
4、过滤相同值的属性
distinct(Projection?proj)
Select distinct o.property from Object o
5、按某个属性分组
groupProperty(String?propertyName)
Criteria crit = session.createCriteria(BasicCar.class)
.setProjection(Projections.groupProperty("name"));
From Object o group by o.property
6、取对象的主键
id()
Select o.id from Object o
7、计算最大值
max(String?propertyName)
Select max(o.property) from Object o
8、计算最小值
min(String?propertyName)
Select min(o.property) from Object o
9、投影某个属性
property(String?propertyName)
Select o.property from Object o
10、计算行数目
rowCount()
Select count(*) from Object o
11、计算总和
sum(String?propertyName)
Select sum(o.property) from Object o
5. Order(重点)
Order类提供对Criteria查询结果集的排序,其静态函数生成升序或降序的Order类,被作为Criteria的参数传给addOrder()方法。
其主要函数有:
static Order asc(String propertyName) 按降序排
static Order desc(String propertyName) 按升序排
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();
8.1.2 使用Expression类和Example类设置查询条件
下面分别介绍Expression类和Example类的查询条件。
1.Expression类(了解)
Expression类由Restrictions工厂类的各个设置条件的静态方法产生。例如,Restrictions类中的gt(String propertyName, Object value)静态方法,用于设置某个属性等于某个值的查询条件,返回的SimpleExpression相当于where propertyName='value'的条件。
方法 |
描述 |
Expression.eq |
对应SQL的“field=value”表达式 如:Expression.eq(“name”,”zx”); |
Expression.allEq |
方法的参数为一个Map类型对象,包含多个名/值对对应关系,相当于多个Expression.eq的叠加 |
Expression.gt |
对应SQL的“field>value”表达式 |
Expression.ge |
对应SQL的“field>=value”表达式 |
Expression.lt |
对应SQL的“field”表达式 |
Expression.le |
对应SQL的“field<=value”表达式 |
Expression.between |
对应SQL语句的between表达式,如:查询年龄在21与27岁之间的用户,可以写成Expression.between(“age”,new Integer(21),new Integer(27)); |
Expression.like |
对应SQL语句的”field like value”表达式 |
Expression.in |
对应SQL语句的“field in(……)”表达式 |
Expression.eqProperty |
用于比较两个属性值,对应”field=field”SQL表达式 |
Expression.gtProperty |
用于比较两个属性值,对应”field>field”SQL表达式 |
Expression.geProperty |
用于比较两个属性值,对应”field>=field”SQL表达式 |
Expression.ltProperty |
用于比较两个属性值,对应”field表达式 |
Expression.leProperty |
用于比较两个属性值,对应”field<=field”SQL表达式 |
Expression.and |
对应SQL语句的And关系组合,如:Expression.and(Expression.eq(“name”,”zx”),Expression.eq(“sex”,”1”)); |
Expression.or |
对应SQL语句的Or关系组合,如:Expression.or(Expression.eq(“name”,”zx”),Expression.eq(“name”,”zhaoxin”)); |
Expression.sql |
作为补充这个方法提供了原生SQL语句查询的支持,在执行时直接通过原生SQL语句进行限定,如:Expression.sql(“lower({alias}.name) like (?)”,“zhao%”,Hibernate.STRING) ;在运行时{ alias }将会由当前查询所关联的实体类名替换,()中的?将会由”zhao%”替换,并且类型由Hibernate.STRING指定。 |
表8-2列出了Restrictions提供的各种条件设置,以及相应的HQL运算符。
表8-2 Restrictions的函数
意 思
Restrictions函数(重点)
HQL例子
1、查询条件逻辑and运算
and(Criterion?lhs, Criterion?rhs)
From Object o where o.property1 = ? and o.property2=?
2、检索在两个数值之间的
between(String?propertyName, Object?lo,
Object?hi)
From Object o where o.property between ? and ?
3、等于
eq(String?propertyName, Object?value)
eqProperty(String?propertyName, String?otherPropertyName)
Eg: List cats = sess.createCriteria(Cat.class) .createAlias("kittens", "kt") .createAlias("mate", "mt") .add( Restrictions.eqProperty("kt.name", "mt.name") ) .list();
From Object o where
o.property=?
4、大于等于
ge(String?propertyName, Object?value)
geProperty(String?propertyName, String?otherPropertyName)
From Object o where
o.property>=?
5、大于
gt(String?propertyName, Object?value)
gtProperty(String?propertyName, String?otherPropertyName)
From Object o where
o.property>?
6、主键等于
idEq(Object?value)
Criteria crit = session.createCriteria(BasicCar.class)
.add( Expression.idEq(new Long(1)) );
From Object o where o.id=?
7、字符串匹配,不区分大小写
islike(String?propertyName, Object?value)
islike(String?propertyName, String?value, MatchMode?matchMode)
Criteria crit = session.createCriteria(BasicCar.class)
.add(Restrictions.islike("name","a", MatchMode.END));
List cats = sess.createCriteria(Cat.class) .add( Restrictions.like("name", "Fritz%") )
From Object o where lower
(o.property) like ??
(续表)
意 思
Restrictions函数
HQL例子
8、范围运算
in(String?propertyName, Collection?values)
in(String?propertyName, Object[]?values)
From Object o where o.property in(‘a’,’b’…)
.add( Restrictions.in( "name", new String[] { "Fritz", "Izi", "Pk" } ) )
9、检查对象的一个集合属性是否为空,也就是在多对多或多对一双向关联中,“一”方对应的“多”方为空,没有关联的
isEmpty(String?propertyName)
From Object o where
o.properties is empty
10、检查对象的一个集合属性是否不为空
isNotEmpty(String?propertyName)
From Object o where
o.properties is not empty
11、一个属性是否不为空
isNotNull(String?propertyName)
From Object o where o.property is not null
12、一个属性是否为空
isNull(String?propertyName)
Criteria crit = session.createCriteria(BasicCar.class)
.add(Restrictions.isNull("name"));
From Object o where o.property
is null
13、小于等于
le(String?propertyName, Object?value)
leProperty(String?propertyName, String?otherPropertyName)
From Object o where
o.property<=?
14、字符串匹配
like(String?propertyName, Object?value)
like(String?propertyName, String?value, MatchMode?matchMode)
Criteria crit = session.createCriteria(BasicCar.class)
.add(Restrictions.like("name","A%"));
From Object o where o.property
like ‘??’
15、小于
lt(String?propertyName, Object?value)
ltProperty(String?propertyName, String?otherPropertyName)
From Object o where
o.property