Hibernate的Criteria和DetachedCriteria 查询

Criteria和DetachedCriteria 查询

最近在项目中使用 Spring 和 Hibernate 进行开发,有感于 Criteria 比较好用,在查询方法


设计上可以灵活的根据 Criteria 的特点来方便地进行查询条件的组装。现在对 Hibernate的Criteria 的用法进行总结:
   Hibernate 设计了 CriteriaSpecification 作为 Criteria 的父接口,下面提供了 Criteria和DetachedCriteria 。
   Criteria 和 DetachedCriteria 的主要区别在于创建的形式不一样, Criteria 是在线的,所
以它是由 Hibernate Session 进行创建的;而 DetachedCriteria 是离线的,创建时无需
Session,DetachedCriteria 提供了 2 个静态方法 forClass(Class) 或 forEntityName(Name)
进行DetachedCriteria 实例的创建。 Spring 的框架提供了getHibernateTemplate
().findByCriteria(detachedCriteria) 方法可以很方便地根据DetachedCriteria 来返回查询结
果。
   Criteria 和 DetachedCriteria 均可使用 Criterion 和 Projection 设置查询条件。可以设
置 FetchMode( 联合查询抓取的模式 ) ,设置排序方式。对于 Criteria 还可以设置 FlushModel
(冲刷 Session 的方式)和 LockMode (数据库锁模式)。
下面对 Criterion 和 Projection 进行详细说明。
     Criterion 是 Criteria 的查询条件。Criteria 提供了 add(Criterion criterion) 方法来
添加查询条件。
     Criterion 接口的主要实现包括: Example 、 Junction 和 SimpleExpression 。而
Junction 的实际使用是它的两个子类 conjunction 和 disjunction ,分别是使用 AND 和 OR 操
作符进行来联结查询条件集合。
     Criterion 的实例可以通过 Restrictions 工具类来创建,Restrictions 提供了大量的静态
方法,如 eq (等于)、 ge (大于等于)、 between 等来方法的创建 Criterion 查询条件
(SimpleExpression 实例)。除此之外, Restrictions 还提供了方法来创建 conjunction 和
disjunction 实例,通过往该实例的 add(Criteria) 方法来增加查询条件形成一个查询条件集合
     至于 Example 的创建有所不同, Example 本身提供了一个静态方法 create(Object
entity) ,即根据一个对象(实际使用中一般是映射到数据库的对象)来创建。然后可以设置一些
过滤条件:
Example exampleUser =Example.create(u)
.ignoreCase() // 忽略大小写
.enableLike(MatchMode.ANYWHERE);
// 对 String 类型的属性,无论在那里值在那里都匹配。相当于 %value%
  Project 主要是让 Criteria 能够进行报表查询,并可以实现分组。 Project 主要有
SimpleProjection 、 ProjectionList 和 Property 三个实现。其中 SimpleProjection 和
ProjectionList 的实例化是由内建的 Projections 来完成,如提供的 avg 、 count 、 max 、
min 、 sum 可以让开发者很容易对某个字段进行统计查询。
       Property 是对某个字段进行查询条件的设置,如通过Porperty.forName(“color”).in
(new String[]{“black”,”red”,”write”}); 则可以创建一个 Project 实例。通过
criteria 的 add(Project) 方法加入到查询条件中去。
    使用 Criteria 进行查询,主要要清晰的是 Hibernate 提供了那些类和方法来满足开发中查
询条件的创建和组装,下面介绍几种用法:
1. 创建一个Criteria 实例
org.hibernate.Criteria接口表示特定持久类的一个查询。Session是 Criteria实例的工厂。
Criteria crit = sess.createCriteria(Cat.class);
crit.setMaxResults(50);
List cats = crit.list();
  
2. 限制结果集内容
一个单独的查询条件是org.hibernate.criterion.Criterion 接口的一个实例。

 

 

 

org.hibernate.criterion.Restrictions类 定义了获得某些内置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提供了相当多的内置criterion类型(Restrictions 子类), 但是尤其有用的是可以允许

你直接使用SQL。

  

List cats = sess.createCriteria(Cat.class)

    .add( Restrictions.sql("lower({alias}.name) like lower(?)", "Fritz%",

Hibernate.STRING) )

    .list();

  

{alias}占位符应当被替换为被查询实体的列别名。

Property实例是获得一个条件的另外一种途径。你可以通过调用Property.forName() 创建一个

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. 结果集排序

你可以使用org.hibernate.criterion.Order来为查询结果排序。

  

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. 关联

你可以使用createCriteria()非常容易的在互相关联的实体间建立 约束。

  

List cats = sess.createCriteria(Cat.class)

    .add( Restrictions.like("name", "F%")

    .createCriteria("kittens")

        .add( Restrictions.like("name", "F%")

    .list();

 

注意第二个 createCriteria()返回一个新的 Criteria实例,该实例引用kittens 集合中的元素。

接下来,替换形态在某些情况下也是很有用的。

  

List cats = sess.createCriteria(Cat.class)

    .createAlias("kittens", "kt")

    .createAlias("mate", "mt")

    .add( Restrictions.eqProperty("kt.name", "mt.name") )

    .list();

 

(createAlias()并不创建一个新的 Criteria实例。)

Cat实例所保存的之前两次查询所返回的kittens集合是 没有被条件预过滤的。如果你希望只获得

符合条件的kittens, 你必须使用returnMaps()。

  

List cats = sess.createCriteria(Cat.class)

    .createCriteria("kittens", "kt")

    .add( Restrictions.eq("name", "F%") )

    .returnMaps()

    .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. 动态关联抓取

你可以使用setFetchMode()在运行时定义动态关联抓取的语义。

  

List cats = sess.createCriteria(Cat.class)

    .add( Restrictions.like("name", "Fritz%") )

    .setFetchMode("mate", FetchMode.EAGER)

    .setFetchMode("kittens", FetchMode.EAGER)

    .list();

  

这个查询可以通过外连接抓取mate和kittens。

  

6. 查询示例

org.hibernate.criterion.Example类允许你通过一个给定实例 构建一个条件查询。

  

Cat cat = new Cat();

cat.setSex('F');

cat.setColor(Color.BLACK);

List results = session.createCriteria(Cat.class)

    .add( Example.create(cat) )

    .list();

 

版本属性、标识符和关联被忽略。默认情况下值为null的属性将被排除。

可以自行调整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在关联对象上放置条件。

  

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 的实例工厂。我们通过调用

setProjection()应用投影到一个查询。

  

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" 。某些投影类型就是被定义为 分组投影,他

们也出现在SQL的group by子句中。

可以选择把一个别名指派给一个投影,这样可以使投影值被约束或排序所引用。下面是两种不同的

实现方式:

  

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范围之外创建一个查询,并且可以使用任意的 Session来

执行它。

  

DetachedCriteria query = DetachedCriteria.forClass(Cat.class)

    .add( Property.forName("sex").eq('F') );

//创建一个Session

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();

相互关联的子查询也是有可能的:

  

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();


Hibernate三大类查询:cretiria,hql,本地sql


 Hibernate目前总共分为三大类查询:cretiria,hql,本地sql 

第一:关于cretiria的查询

   具有一个直观的、可扩展的条件查询API是Hibernate的特色。 

15.1. 创建一个Criteria 实例
org.hibernate.Criteria接口表示特定持久类的一个查询。Session是 Criteria实例的工厂。

Java代码  复制代码
  1. <SPAN style="FONT-SIZE: medium">Criteria crit = sess.createCriteria(Cat.class);   
  2. crit.setMaxResults(50);   
  3. List cats = crit.list();</SPAN>  
Java代码   收藏代码
  1. <span style="font-size: medium;">Criteria crit = sess.createCriteria(Cat.class);  
  2. crit.setMaxResults(50);  
  3. List cats = crit.list();</span>  

 
15.2. 限制结果集内容
一个单独的查询条件是org.hibernate.criterion.Criterion 接口的一个实例。org.hibernate.criterion.Restrictions类 定义了获得某些内置Criterion类型的工厂方法。

Java代码  复制代码
  1. <SPAN style="FONT-SIZE: medium">List cats = sess.createCriteria(Cat.class)   
  2.      .add( Restrictions.like("name""Fritz%") )   
  3.      .add( Restrictions.between("weight", minWeight, maxWeight) )   
  4.      .list();   
  5. </SPAN>  
Java代码   收藏代码
  1. <span style="font-size: medium;">List cats = sess.createCriteria(Cat.class)  
  2.      .add( Restrictions.like("name""Fritz%") )  
  3.      .add( Restrictions.between("weight", minWeight, maxWeight) )  
  4.      .list();  
  5. </span>  

 
约束可以按逻辑分组。

Java代码  复制代码
  1. <SPAN style="FONT-SIZE: medium">List cats = sess.createCriteria(Cat.class)   
  2.      .add( Restrictions.like("name""Fritz%") )   
  3.      .add( Restrictions.or(   
  4.          Restrictions.eq( "age"new Integer(0) ),   
  5.          Restrictions.isNull("age")   
  6.      ) )   
  7.      .list();   
  8. List cats = sess.createCriteria(Cat.class)   
  9.      .add( Restrictions.in( "name"new String[] { "Fritz""Izi""Pk" } ) )   
  10.      .add( Restrictions.disjunction()   
  11.          .add( Restrictions.isNull("age") )   
  12.       .add( Restrictions.eq("age"new Integer(0) ) )   
  13.       .add( Restrictions.eq("age"new Integer(1) ) )   
  14.       .add( Restrictions.eq("age"new Integer(2) ) )   
  15.      ) )   
  16.      .list();</SPAN>  
Java代码   收藏代码
  1. <span style="font-size: medium;">List cats = sess.createCriteria(Cat.class)  
  2.      .add( Restrictions.like("name""Fritz%") )  
  3.      .add( Restrictions.or(  
  4.          Restrictions.eq( "age"new Integer(0) ),  
  5.          Restrictions.isNull("age")  
  6.      ) )  
  7.      .list();  
  8. List cats = sess.createCriteria(Cat.class)  
  9.      .add( Restrictions.in( "name"new String[] { "Fritz""Izi""Pk" } ) )  
  10.      .add( Restrictions.disjunction()  
  11.          .add( Restrictions.isNull("age") )  
  12.       .add( Restrictions.eq("age"new Integer(0) ) )  
  13.       .add( Restrictions.eq("age"new Integer(1) ) )  
  14.       .add( Restrictions.eq("age"new Integer(2) ) )  
  15.      ) )  
  16.      .list();</span>  

 
Hibernate提供了相当多的内置criterion类型(Restrictions 子类), 但是尤其有用的是可以允许你直接使用SQL。

 

Java代码  复制代码
  1. <SPAN style="FONT-SIZE: medium">List cats = sess.createCriteria(Cat.class)   
  2.      .add( Restrictions.sql("lower({alias}.name) like lower(?)""Fritz%", Hibernate.STRING) )   
  3.      .list();   
  4. </SPAN>  
Java代码   收藏代码
  1. <span style="font-size: medium;">List cats = sess.createCriteria(Cat.class)  
  2.      .add( Restrictions.sql("lower({alias}.name) like lower(?)""Fritz%", Hibernate.STRING) )  
  3.      .list();  
  4. </span>  

 


{alias}占位符应当被替换为被查询实体的列别名。 

Property实例是获得一个条件的另外一种途径。你可以通过调用Property.forName() 创建一个Property。

Java代码  复制代码
  1. <SPAN style="FONT-SIZE: medium">Property age = Property.forName("age");   
  2. List cats = sess.createCriteria(Cat.class)   
  3.      .add( Restrictions.disjunction()   
  4.          .add( age.isNull() )   
  5.       .add( age.eq( new Integer(0) ) )   
  6.       .add( age.eq( new Integer(1) ) )   
  7.       .add( age.eq( new Integer(2) ) )   
  8.      ) )   
  9.      .add( Property.forName("name").in( new String[] { "Fritz""Izi""Pk" } ) )   
  10.      .list();</SPAN>  
Java代码   收藏代码
  1. <span style="font-size: medium;">Property age = Property.forName("age");  
  2. List cats = sess.createCriteria(Cat.class)  
  3.      .add( Restrictions.disjunction()  
  4.          .add( age.isNull() )  
  5.       .add( age.eq( new Integer(0) ) )  
  6.       .add( age.eq( new Integer(1) ) )  
  7.       .add( age.eq( new Integer(2) ) )  
  8.      ) )  
  9.      .add( Property.forName("name").in( new String[] { "Fritz""Izi""Pk" } ) )  
  10.      .list();</span>  

 
15.3. 结果集排序
你可以使用org.hibernate.criterion.Order来为查询结果排序。

Java代码  复制代码
  1. <SPAN style="FONT-SIZE: medium">List cats = sess.createCriteria(Cat.class)   
  2.      .add( Restrictions.like("name""F%")   
  3.      .addOrder( Order.asc("name") )   
  4.      .addOrder( Order.desc("age") )   
  5.      .setMaxResults(50)   
  6.      .list();   
  7. List cats = sess.createCriteria(Cat.class)   
  8.      .add( Property.forName("name").like("F%") )   
  9.      .addOrder( Property.forName("name").asc() )   
  10.      .addOrder( Property.forName("age").desc() )   
  11.      .setMaxResults(50)   
  12.      .list();   
  13. </SPAN>  
Java代码   收藏代码
  1. <span style="font-size: medium;">List cats = sess.createCriteria(Cat.class)  
  2.      .add( Restrictions.like("name""F%")  
  3.      .addOrder( Order.asc("name") )  
  4.      .addOrder( Order.desc("age") )  
  5.      .setMaxResults(50)  
  6.      .list();  
  7. List cats = sess.createCriteria(Cat.class)  
  8.      .add( Property.forName("name").like("F%") )  
  9.      .addOrder( Property.forName("name").asc() )  
  10.      .addOrder( Property.forName("age").desc() )  
  11.      .setMaxResults(50)  
  12.      .list();  
  13. </span>  

 

15.4. 关联
你可以使用createCriteria()非常容易的在互相关联的实体间建立 约束。 
 

Java代码  复制代码
  1. <SPAN style="FONT-SIZE: medium">List cats = sess.createCriteria(Cat.class)   
  2.      .add( Restrictions.like("name""F%")   
  3.      .createCriteria("kittens")   
  4.          .add( Restrictions.like("name""F%")   
  5.      .list();   
  6. </SPAN>  
Java代码   收藏代码
  1. <span style="font-size: medium;">List cats = sess.createCriteria(Cat.class)  
  2.      .add( Restrictions.like("name""F%")  
  3.      .createCriteria("kittens")  
  4.          .add( Restrictions.like("name""F%")  
  5.      .list();  
  6. </span>  

 

注意第二个 createCriteria()返回一个新的 Criteria实例,该实例引用kittens 集合中的元素。 

接下来,替换形态在某些情况下也是很有用的。

Java代码  复制代码
  1. <SPAN style="FONT-SIZE: medium">List cats = sess.createCriteria(Cat.class)   
  2.      .createAlias("kittens""kt")   
  3.      .createAlias("mate""mt")   
  4.      .add( Restrictions.eqProperty("kt.name""mt.name") )   
  5.      .list();   
  6. </SPAN>  
Java代码   收藏代码
  1. <span style="font-size: medium;">List cats = sess.createCriteria(Cat.class)  
  2.      .createAlias("kittens""kt")  
  3.      .createAlias("mate""mt")  
  4.      .add( Restrictions.eqProperty("kt.name""mt.name") )  
  5.      .list();  
  6. </span>  

 

(createAlias()并不创建一个新的 Criteria实例。) 

Cat实例所保存的之前两次查询所返回的kittens集合是 没有被条件预过滤的。如果你希望只获得符合条件的kittens, 你必须使用returnMaps()。

Java代码  复制代码
  1. <SPAN style="FONT-SIZE: medium">List cats = sess.createCriteria(Cat.class)   
  2.      .createCriteria("kittens""kt")   
  3.          .add( Restrictions.eq("name""F%") )   
  4.      .returnMaps()   
  5.      .list();   
  6. Iterator iter = cats.iterator();   
  7. while ( iter.hasNext() ) {   
  8.      Map map = (Map) iter.next();   
  9.      Cat cat = (Cat) map.get(Criteria.ROOT_ALIAS);   
  10.      Cat kitten = (Cat) map.get("kt");   
  11. }   
  12. </SPAN>  
Java代码   收藏代码
  1. <span style="font-size: medium;">List cats = sess.createCriteria(Cat.class)  
  2.      .createCriteria("kittens""kt")  
  3.          .add( Restrictions.eq("name""F%") )  
  4.      .returnMaps()  
  5.      .list();  
  6. Iterator iter = cats.iterator();  
  7. while ( iter.hasNext() ) {  
  8.      Map map = (Map) iter.next();  
  9.      Cat cat = (Cat) map.get(Criteria.ROOT_ALIAS);  
  10.      Cat kitten = (Cat) map.get("kt");  
  11. }  
  12. </span>  

 

15.5. 动态关联抓取
你可以使用setFetchMode()在运行时定义动态关联抓取的语义。

Java代码  复制代码
  1. <SPAN style="FONT-SIZE: medium">List cats = sess.createCriteria(Cat.class)   
  2.      .add( Restrictions.like("name""Fritz%") )   
  3.      .setFetchMode("mate", FetchMode.EAGER)   
  4.      .setFetchMode("kittens", FetchMode.EAGER)   
  5.      .list();   
  6. </SPAN>  
Java代码   收藏代码
  1. <span style="font-size: medium;">List cats = sess.createCriteria(Cat.class)  
  2.      .add( Restrictions.like("name""Fritz%") )  
  3.      .setFetchMode("mate", FetchMode.EAGER)  
  4.      .setFetchMode("kittens", FetchMode.EAGER)  
  5.      .list();  
  6. </span>  

 

这个查询可以通过外连接抓取mate和kittens。 查看第 19.1 节 “ 抓取策略(Fetching strategies) ”可以获得更多信息。 

15.6. 查询示例
org.hibernate.criterion.Example类允许你通过一个给定实例 构建一个条件查询。

Java代码  复制代码
  1. <SPAN style="FONT-SIZE: medium">Cat cat = new Cat();   
  2. cat.setSex('F');   
  3. cat.setColor(Color.BLACK);   
  4. List results = session.createCriteria(Cat.class)   
  5.      .add( Example.create(cat) )   
  6.      .list();</SPAN>  
Java代码   收藏代码
  1. <span style="font-size: medium;">Cat cat = new Cat();  
  2. cat.setSex('F');  
  3. cat.setColor(Color.BLACK);  
  4. List results = session.createCriteria(Cat.class)  
  5.      .add( Example.create(cat) )  
  6.      .list();</span>  

 
版本属性、标识符和关联被忽略。默认情况下值为null的属性将被排除。 

你可以自行调整Example使之更实用。

Java代码  复制代码
  1. <SPAN style="FONT-SIZE: medium">Example example = Example.create(cat)   
  2.      .excludeZeroes()            //exclude zero valued properties   
  3.      .excludeProperty("color")   //exclude the property named "color"   
  4.      .ignoreCase()               //perform case insensitive string comparisons   
  5.      .enableLike();              //use like for string comparisons   
  6. List results = session.createCriteria(Cat.class)   
  7.      .add(example)   
  8.      .list();</SPAN>  
Java代码   收藏代码
  1. <span style="font-size: medium;">Example example = Example.create(cat)  
  2.      .excludeZeroes()            //exclude zero valued properties  
  3.      .excludeProperty("color")   //exclude the property named "color"  
  4.      .ignoreCase()               //perform case insensitive string comparisons  
  5.      .enableLike();              //use like for string comparisons  
  6. List results = session.createCriteria(Cat.class)  
  7.      .add(example)  
  8.      .list();</span>  

 
你甚至可以使用examples在关联对象上放置条件。

Java代码  复制代码
  1. <SPAN style="FONT-SIZE: medium">List results = session.createCriteria(Cat.class)   
  2.      .add( Example.create(cat) )   
  3.      .createCriteria("mate")   
  4.          .add( Example.create( cat.getMate() ) )   
  5.      .list();   
  6. </SPAN>  
Java代码   收藏代码
  1. <span style="font-size: medium;">List results = session.createCriteria(Cat.class)  
  2.      .add( Example.create(cat) )  
  3.      .createCriteria("mate")  
  4.          .add( Example.create( cat.getMate() ) )  
  5.      .list();  
  6. </span>  

 

15.7. 投影(Projections)、聚合(aggregation)和分组(grouping)
org.hibernate.criterion.Projections是 Projection 的实例工厂。我们通过调用 setProjection()应用投影到一个查询。 

在一个条件查询中没有必要显式的使用 "group by" 。某些投影类型就是被定义为 分组投影,他们也出现在SQL的group by子句中。 

你可以选择把一个别名指派给一个投影,这样可以使投影值被约束或排序所引用。下面是两种不同的实现方式:

Java代码  复制代码
  1. <SPAN style="FONT-SIZE: medium">List results = session.createCriteria(Cat.class)   
  2.      .setProjection( Projections.alias( Projections.groupProperty("color"), "colr" ) )   
  3.      .addOrder( Order.asc("colr") )   
  4.      .list();   
  5. List results = session.createCriteria(Cat.class)   
  6.      .setProjection( Projections.groupProperty("color").as("colr") )   
  7.      .addOrder( Order.asc("colr") )   
  8.      .list();   
  9. </SPAN>  
Java代码   收藏代码
  1. <span style="font-size: medium;">List results = session.createCriteria(Cat.class)  
  2.      .setProjection( Projections.alias( Projections.groupProperty("color"), "colr" ) )  
  3.      .addOrder( Order.asc("colr") )  
  4.      .list();  
  5. List results = session.createCriteria(Cat.class)  
  6.      .setProjection( Projections.groupProperty("color").as("colr") )  
  7.      .addOrder( Order.asc("colr") )  
  8.      .list();  
  9. </span>  

 

alias()和as()方法简便的将一个投影实例包装到另外一个 别名的Projection实例中。简而言之,当你添加一个投影到一个投影列表中时 你可以为它指定一个别名:

Java代码  复制代码
  1. <SPAN style="FONT-SIZE: medium">List results = session.createCriteria(Cat.class)   
  2.      .setProjection( Projections.projectionList()   
  3.          .add( Projections.rowCount(), "catCountByColor" )   
  4.          .add( Projections.avg("weight"), "avgWeight" )   
  5.          .add( Projections.max("weight"), "maxWeight" )   
  6.          .add( Projections.groupProperty("color"), "color" )   
  7.      )   
  8.      .addOrder( Order.desc("catCountByColor") )   
  9.      .addOrder( Order.desc("avgWeight") )   
  10.      .list();   
  11. List results = session.createCriteria(Domestic.class"cat")   
  12.      .createAlias("kittens""kit")   
  13.      .setProjection( Projections.projectionList()   
  14.          .add( Projections.property("cat.name"), "catName" )   
  15.          .add( Projections.property("kit.name"), "kitName" )   
  16.      )   
  17.      .addOrder( Order.asc("catName") )   
  18.      .addOrder( Order.asc("kitName") )   
  19.      .list();</SPAN>  
Java代码   收藏代码
  1. <span style="font-size: medium;">List results = session.createCriteria(Cat.class)  
  2.      .setProjection( Projections.projectionList()  
  3.          .add( Projections.rowCount(), "catCountByColor" )  
  4.          .add( Projections.avg("weight"), "avgWeight" )  
  5.          .add( Projections.max("weight"), "maxWeight" )  
  6.          .add( Projections.groupProperty("color"), "color" )  
  7.      )  
  8.      .addOrder( Order.desc("catCountByColor") )  
  9.      .addOrder( Order.desc("avgWeight") )  
  10.      .list();  
  11. List results = session.createCriteria(Domestic.class"cat")  
  12.      .createAlias("kittens""kit")  
  13.      .setProjection( Projections.projectionList()  
  14.          .add( Projections.property("cat.name"), "catName" )  
  15.          .add( Projections.property("kit.name"), "kitName" )  
  16.      )  
  17.      .addOrder( Order.asc("catName") )  
  18.      .addOrder( Order.asc("kitName") )  
  19.      .list();</span>  

 
你也可以使用Property.forName()来表示投影:

Java代码  复制代码
  1. <SPAN style="FONT-SIZE: medium">List results = session.createCriteria(Cat.class)   
  2.      .setProjection( Property.forName("name") )   
  3.      .add( Property.forName("color").eq(Color.BLACK) )   
  4.      .list();   
  5. List results = session.createCriteria(Cat.class)   
  6.      .setProjection( Projections.projectionList()   
  7.          .add( Projections.rowCount().as("catCountByColor") )   
  8.          .add( Property.forName("weight").avg().as("avgWeight") )   
  9.          .add( Property.forName("weight").max().as("maxWeight") )   
  10.          .add( Property.forName("color").group().as("color" )   
  11.      )   
  12.      .addOrder( Order.desc("catCountByColor") )   
  13.      .addOrder( Order.desc("avgWeight") )   
  14.      .list();</SPAN>  
Java代码   收藏代码
  1. <span style="font-size: medium;">List results = session.createCriteria(Cat.class)  
  2.      .setProjection( Property.forName("name") )  
  3.      .add( Property.forName("color").eq(Color.BLACK) )  
  4.      .list();  
  5. List results = session.createCriteria(Cat.class)  
  6.      .setProjection( Projections.projectionList()  
  7.          .add( Projections.rowCount().as("catCountByColor") )  
  8.          .add( Property.forName("weight").avg().as("avgWeight") )  
  9.          .add( Property.forName("weight").max().as("maxWeight") )  
  10.          .add( Property.forName("color").group().as("color" )  
  11.      )  
  12.      .addOrder( Order.desc("catCountByColor") )  
  13.      .addOrder( Order.desc("avgWeight") )  
  14.      .list();</span>  

 
15.8. 离线(detached)查询和子查询
DetachedCriteria类使你在一个session范围之外创建一个查询,并且可以使用任意的 Session来执行它。

Java代码  复制代码
  1. <SPAN style="FONT-SIZE: medium">DetachedCriteria query = DetachedCriteria.forClass(Cat.class)   
  2.      .add( Property.forName("sex").eq('F') );   
  3.        
  4. Session session = ....;   
  5. Transaction txn = session.beginTransaction();   
  6. List results = query.getExecutableCriteria(session).setMaxResults(100).list();   
  7. txn.commit();   
  8. session.close();   
  9. DetachedCriteria也可以用以表示子查询。条件实例包含子查询可以通过 Subqueries或者Property获得。    
  10.   
  11. DetachedCriteria avgWeight = DetachedCriteria.forClass(Cat.class)   
  12. .setProjection( Property.forName("weight").avg() );   
  13. session.createCriteria(Cat.class)   
  14. .add( Property.forName("weight).gt(avgWeight) )   
  15. .list();   
  16. DetachedCriteria weights = DetachedCriteria.forClass(Cat.class)   
  17. .setProjection( Property.forName("weight") );   
  18. session.createCriteria(Cat.class)   
  19. .add( Subqueries.geAll("weight", weights) )   
  20. .list();</SPAN>  
Java代码   收藏代码
  1. <span style="font-size: medium;">DetachedCriteria query = DetachedCriteria.forClass(Cat.class)  
  2.      .add( Property.forName("sex").eq('F') );  
  3.       
  4. Session session = ....;  
  5. Transaction txn = session.beginTransaction();  
  6. List results = query.getExecutableCriteria(session).setMaxResults(100).list();  
  7. txn.commit();  
  8. session.close();  
  9. DetachedCriteria也可以用以表示子查询。条件实例包含子查询可以通过 Subqueries或者Property获得。   
  10.   
  11. DetachedCriteria avgWeight = DetachedCriteria.forClass(Cat.class)  
  12. .setProjection( Property.forName("weight").avg() );  
  13. session.createCriteria(Cat.class)  
  14. .add( Property.forName("weight).gt(avgWeight) )  
  15. .list();  
  16. DetachedCriteria weights = DetachedCriteria.forClass(Cat.class)  
  17. .setProjection( Property.forName("weight") );  
  18. session.createCriteria(Cat.class)  
  19. .add( Subqueries.geAll("weight", weights) )  
  20. .list();</span>  

 
甚至相互关联的子查询也是有可能的:

Java代码  复制代码
  1. <SPAN style="FONT-SIZE: medium">DetachedCriteria avgWeightForSex = DetachedCriteria.forClass(Cat.class"cat2")   
  2. .setProjection( Property.forName("weight").avg() )   
  3. .add( Property.forName("cat2.sex").eqProperty("cat.sex") );   
  4. session.createCriteria(Cat.class"cat")   
  5. .add( Property.forName("weight).gt(avgWeightForSex) )   
  6. .list();</SPAN>  
Java代码   收藏代码
  1. <span style="font-size: medium;">DetachedCriteria avgWeightForSex = DetachedCriteria.forClass(Cat.class"cat2")  
  2. .setProjection( Property.forName("weight").avg() )  
  3. .add( Property.forName("cat2.sex").eqProperty("cat.sex") );  
  4. session.createCriteria(Cat.class"cat")  
  5. .add( Property.forName("weight).gt(avgWeightForSex) )  
  6. .list();</span>  

 

 

第二:HQL查询

在HQL中关键字不区分大小写,但是属性和类名区分大小写,下面介绍各种类型的Hibernate的HQL查询。
1、Hibernate HQL查询:简单属性查询

* 单一属性查询,返回结果集属性列表,元素类型和实体类中相应的属性类型一致

* 多个属性查询,返回的集合元素是对象数组,数组元素的类型和对应的属性在实体类中的类型一致 
数组的长度取决与select中属性的个数

* 如果认为返回数组不够对象化,可以采用HQL动态实例化Student对象

2、Hibernate HQL查询:实体对象查询

* N + 1问题,在默认情况下,使用query.iterate查询,有可以能出现N+1问题,所谓的N+1是在查询的时候发出了N+1条sql语句,1: 首先发出一条查询对象id列表的sql,N: 根据id列表到缓存中查询,如果缓存中不存在与之匹配的数据,那么会根据id发出相应的sql语句

* list和iterate的区别?

* list每次都会发出sql语句,list会向缓存中放入数据,而不利用缓存中的数据

* iterate:在默认情况下iterate利用缓存数据,但如果缓存中不存在数据有可以能出现N+1问题

3、Hibernate HQL查询:条件查询

* 可以采用拼字符串的方式传递参数

Java代码:

Java代码  复制代码
  1. <SPAN style="FONT-SIZE: medium">List students = session.createQuery("select s.id, s.name from Student s where s.name like '%1%'").list();   </SPAN>  
Java代码   收藏代码
  1. <span style="font-size: medium;">List students = session.createQuery("select s.id, s.name from Student s where s.name like '%1%'").list();   </span>  

 

* 可以采用 ?来传递参数(索引从0开始)

Java代码:

Java代码  复制代码
  1. <SPAN style="FONT-SIZE: medium">List students = session.createQuery("select s.id, s.name from Student s where s.name like ?").setParameter(0"%1%").list();      //可以使用?方式传递参数      //参数的索引从0开始      //传递的参数值,不用单引号引起来      //注意方法链编程    </SPAN>  
Java代码   收藏代码
  1. <span style="font-size: medium;">List students = session.createQuery("select s.id, s.name from Student s where s.name like ?").setParameter(0"%1%").list();      //可以使用?方式传递参数      //参数的索引从0开始      //传递的参数值,不用单引号引起来      //注意方法链编程    </span>  

  

* 可以采用 :参数名 来传递参数

Java代码:

 

Java代码  复制代码
  1. <SPAN style="FONT-SIZE: medium">List students = session.createQuery  ("select s.id, s.name from Student s where s.name like :myname").setParameter("myname""%1%").list();    </SPAN>  
Java代码   收藏代码
  1. <span style="font-size: medium;">List students = session.createQuery  ("select s.id, s.name from Student s where s.name like :myname").setParameter("myname""%1%").list();    </span>  

 

* 如果传递多个参数,可以采用setParamterList方法

Java代码: 

    

Java代码  复制代码
  1. <SPAN style="FONT-SIZE: medium">List students = session.createQuery("select s.id, s.name from Student s where s.id in(:myids)").setParameterList("myids"new Object[]{12345}).list();</SPAN>  
Java代码   收藏代码
  1. <span style="font-size: medium;">List students = session.createQuery("select s.id, s.name from Student s where s.id in(:myids)").setParameterList("myids"new Object[]{12345}).list();</span>  

 

* 在HQL中可以使用数据库的函数,如:date_format

Java代码:

Java代码  复制代码
  1. <SPAN style="FONT-SIZE: medium">List students = session.createQuery("select s.id, s.name from Student s where date_format(s.createTime, '%Y-%m')=?").setParameter(0"2008-02").list();      SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");                  //查询2008-01-10到2008-02-15创建的学生          List students = session.createQuery("select s.id, s.name from Student s where s.createTime between ? and ?")                .setParameter(0, sdf.parse("2008-01-10 00:00:00"))                .setParameter(1, sdf.parse("2008-02-15 23:59:59"))                      .list();     </SPAN>  
Java代码   收藏代码
  1. <span style="font-size: medium;">List students = session.createQuery("select s.id, s.name from Student s where date_format(s.createTime, '%Y-%m')=?").setParameter(0"2008-02").list();      SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");                  //查询2008-01-10到2008-02-15创建的学生          List students = session.createQuery("select s.id, s.name from Student s where s.createTime between ? and ?")                .setParameter(0, sdf.parse("2008-01-10 00:00:00"))                .setParameter(1, sdf.parse("2008-02-15 23:59:59"))                      .list();     </span>  

 

4、Hibernate HQL查询:直接使用sql进行查询

Java代码:

  

Java代码  复制代码
  1. <SPAN style="FONT-SIZE: medium">List students = session.createSQLQuery("select * from t_student").list();   </SPAN>  
Java代码   收藏代码
  1. <span style="font-size: medium;">List students = session.createSQLQuery("select * from t_student").list();   </span>  

 
不会返回对象,而是所有属性!  


5、Hibernate HQL查询:分页查询

* setFirstResult(),从0开始

* setMaxResults,每页显示多少条数据

Java代码:

Java代码  复制代码
  1. <SPAN style="FONT-SIZE: medium">List students = session.createQuery("from Student")                .setFirstResult(1)                .setMaxResults(2)                .list();    </SPAN>  
Java代码   收藏代码
  1. <span style="font-size: medium;">List students = session.createQuery("from Student")                .setFirstResult(1)                .setMaxResults(2)                .list();    </span>  

 

6、Hibernate HQL查询:对象导航查询,在HQL中采用 . 进行导航

7、Hibernate HQL查询:连接查询

* 内连

Sql代码:  

Java代码  复制代码
  1. <SPAN style="FONT-SIZE: medium">SELECT s.name, c.name FROM Student s (inner) join s.classes c    </SPAN>  
Java代码   收藏代码
  1. <span style="font-size: medium;">SELECT s.name, c.name FROM Student s (inner) join s.classes c    </span>  

 

* 外连接(左连接/右连接)

Sql代码:

Java代码  复制代码
  1. <SPAN style="FONT-SIZE: medium">SELECT s.name, c.name FROM Student s left join s.classes c   </SPAN>  
Java代码   收藏代码
  1. <span style="font-size: medium;">SELECT s.name, c.name FROM Student s left join s.classes c   </span>  

  

 

 

8、Hibernate HQL查询:统计查询

Java代码:

Java代码  复制代码
  1. <SPAN style="FONT-SIZE: medium">List students =session.createQuery("select c.name, count(s) from Student s join s.classes c " +"group by c.name order by c.name").list();      for (Iterator iter=students.iterator(); iter.hasNext();) {           Object[] obj = (Object[])iter.next();           System.out.println(obj[0] + ", " + obj[1]);      }  </SPAN>  
Java代码   收藏代码
  1. <span style="font-size: medium;">List students =session.createQuery("select c.name, count(s) from Student s join s.classes c " +"group by c.name order by c.name").list();      for (Iterator iter=students.iterator(); iter.hasNext();) {           Object[] obj = (Object[])iter.next();           System.out.println(obj[0] + ", " + obj[1]);      }  </span>  

 

9、DML风格的操作(尽量少用,因为和缓存不同步)

Java代码:

Java代码  复制代码
  1. <SPAN style="FONT-SIZE: medium">session.createQuery  ("update Student s set s.name=? where s.id < ?")                           .setParameter(0"李四")                           .setParameter(15)                           .executeUpdate();    </SPAN>  
Java代码   收藏代码
  1. <span style="font-size: medium;">session.createQuery  ("update Student s set s.name=? where s.id < ?")                           .setParameter(0"李四")                           .setParameter(15)                           .executeUpdate();    </span>  

 

应当尽量少用,因为和缓存不同步,也就是说,假如在执行上面的语句之前,已经把student封装成一个list曾经拿了出来,再执行上面的语句对 student中的表进行数据更新,然后再list Student表,则此时的list是从缓存中取的数据,而不是从表中找到的数据,也就是说,list拿到的是update前的数据,所以造成了这种不同步,所以这种风格尽量少用。

从这个方面也可以看得出Hibernate并不适用于聚集性,统计,大量批量的更新,删除等操作。

 

第三,本地SQL查询

使用SQLQuery
对原生SQL查询执行的控制是通过SQLQuery接口进行的,通过执行Session.createSQLQuery()获取这个接口。最简单的情况下,我们可以采用以下形式:

Java代码  复制代码
  1. <SPAN style="FONT-SIZE: medium">List cats  =  sess.createSQLQuery( " select * from cats " ).addEntity(Cat. class ).list(); </SPAN>  
Java代码   收藏代码
  1. <span style="font-size: medium;">List cats  =  sess.createSQLQuery( " select * from cats " ).addEntity(Cat. class ).list(); </span>  

 

这个查询指定了:

SQL查询字符串

查询返回的实体

这里,结果集字段名被假设为与映射文件中指明的字段名相同。对于连接了多个表的查询,这就可能造成问题,因为可能在多个表中出现同样名字的字段。下面的方法就可以避免字段名重复的问题:

Java代码  复制代码
  1. <SPAN style="FONT-SIZE: medium">List cats  =  sess.createSQLQuery( " select {cat.*} from cats cat " ).addEntity( " cat " , Cat. class ).list(); </SPAN>  
Java代码   收藏代码
  1. <span style="font-size: medium;">List cats  =  sess.createSQLQuery( " select {cat.*} from cats cat " ).addEntity( " cat " , Cat. class ).list(); </span>  

 

这个查询指定了:

SQL查询语句,它带一个占位符,可以让Hibernate使用字段的别名.

查询返回的实体,和它的SQL表的别名.

addEntity()方法将SQL


离线查询和子查询--DetachedCriteria 例子

DetachedCriteria类使你在一个session范围之外创建一个查询,并且可以使用任意的 Session来执行它。

配置实体类Student 以及Student.hbm.xml映射文件

  1. package sun.domain;  
  2.   
  3. import java.util.*;  
  4.   
  5. public class Student  
  6. {  
  7.     private Integer studentNumber;  
  8.     private String name;  
  9.     private Set<Enrolment> enrolments  
  10.         = new HashSet<Enrolment>();     
  11.     public Student()  
  12.     {  
  13.     }  
  14.     public Student(Integer studentNumber , String name)  
  15.     {  
  16.         this.studentNumber = studentNumber;  
  17.         this.name = name;  
  18.     }  
  19.       
  20.     public void setStudentNumber(Integer studentNumber)  
  21.     {  
  22.         this.studentNumber = studentNumber;  
  23.     }  
  24.     public Integer getStudentNumber()  
  25.     {  
  26.         return this.studentNumber;  
  27.     }  
  28.       
  29.     public void setName(String name)  
  30.     {  
  31.         this.name = name;  
  32.     }  
  33.     public String getName()  
  34.     {  
  35.         return this.name;  
  36.     }  
  37.       
  38.     public void setEnrolments(Set<Enrolment> enrolments)  
  39.     {  
  40.         this.enrolments = enrolments;  
  41.     }  
  42.     public Set<Enrolment> getEnrolments()  
  43.     {  
  44.         return this.enrolments;  
  45.     }  
  46. }  

  1. <?xml version="1.0" encoding="GBK"?>  
  2. <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"  
  3.                                    "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">  
  4. <!-- 指定Hibernate映射文件的DTD信息 -->  
  5. <hibernate-mapping package="sun.domain">  
  6.  <!-- 映射Student实体 -->  
  7.  <class name="Student" table="student_inf">  
  8.   <!-- 映射标识属性 -->  
  9.   <id column="student_id" name="studentNumber">  
  10.    <!-- 指定assigned的主键生成器策略 -->  
  11.    <generator class="assigned"/>  
  12.   </id>  
  13.   <!-- 映射普通属性 -->  
  14.   <property generated="never" lazy="false" name="name" not-null="true"/>  
  15.   <!-- 映射学生和选课记录的1-N关联 -->  
  16.   <set cascade="delete" inverse="true" name="enrolments" sort="unsorted">  
  17.    <!-- 映射外键 -->  
  18.    <key column="student_id"/>  
  19.    <!-- 映射关联的Enrolment实体 -->  
  20.    <one-to-many class="Enrolment"/>  
  21.   </set>  
  22.  </class>  
  23. </hibernate-mapping>  

HibernateUtil我就不写了,可以在MyEclipse中自动生成


测试类

  1. package sun.test;  
  2.   
  3. import java.util.Iterator;  
  4. import java.util.List;  
  5.   
  6. import org.hibernate.Session;  
  7. import org.hibernate.criterion.DetachedCriteria;  
  8. import org.hibernate.criterion.Property;  
  9.   
  10. import sun.domain.Student;  
  11. import sun.util.HibernateUtil;  
  12.   
  13. public class DetachedCriteriaTest {  
  14.     public static void main(String[] args) {  
  15.         DetachedCriteriaTest pt = new DetachedCriteriaTest();  
  16.         pt.datached();  
  17.         pt.subQuery();  
  18.     }  
  19.   
  20.     /** 
  21.      * 子查询 
  22.      */  
  23.     private void subQuery() {  
  24.         //定义一个离线查询  
  25.         DetachedCriteria subQuery = DetachedCriteria.forClass(Student.class)  
  26.                 .setProjection(Property.forName("name"));  
  27.         Session session = HibernateUtil.getSession();  
  28.         HibernateUtil.beginTransaction();  
  29.         List l = session.createCriteria(Student.class)  
  30.             .add(Property.forName("name").in(subQuery)).list();  
  31.         for (Iterator iterator = l.iterator(); iterator.hasNext();) {  
  32.             Student stu = (Student) iterator.next();  
  33.             System.out.println(stu.getName());  
  34.         }  
  35.         HibernateUtil.commit();  
  36.         HibernateUtil.closeSession();  
  37.     }  
  38.   
  39.     /** 
  40.      * 离线查询 
  41.      */  
  42.     private void datached() {  
  43.         DetachedCriteria query = DetachedCriteria.forClass(Student.class)  
  44.                 .setProjection(Property.forName("name"));  
  45.         Session session = HibernateUtil.getSession();  
  46.         HibernateUtil.beginTransaction();  
  47.         List l = query.getExecutableCriteria(session).list();  
  48.         for (Iterator iterator = l.iterator(); iterator.hasNext();) {  
  49.             System.out.println(iterator.next());  
  50.         }  
  51.         HibernateUtil.commit();  
  52.         HibernateUtil.closeSession();  
  53.     }  
  54. }  


运行结果:




Hibernate几种查询方式对比

HQL查询方式

这一种我最常用,也是最喜欢用的,因为它写起来灵活直观,而且与所熟悉的SQL的语法差不太多。条件查询、分页查询、连接查询、嵌套查询,写起来与SQL语法基本一致,唯一不同的就是把表名换成了类或者对象。其它的,包括一些查询函数(count(),sum()等)、查询条件的设定等,全都跟SQL语法一样。

示例:
   1: Session session = SessionFactory.getCurrentSession();
   2: User user = null;
   3: Transaction ts = session.beginTransaction();
   4: try {
   5:     Query query = session.createQuery("from User as u where name='ijse'");
   6:     user= (User) query.list().get(0);
   7:     session.commit();
   8: } catch (HibernateException ex) {
   9:     ts.rollBack();
  10:     ex.printStackTrace();
  11: }
  12: System.out.println(user.getName());

QBC(Query By Criteria) 查询方式

这种方式比较面向对象方式,重点是有三个描述条件的对象:Restrictions,Order,Projections。使用QBC查询,一般需要以下三个步骤:

  1. 使用Session实例 的createCriteria()方法创建Criteria对象
  2. 使用工具类Restrictions的方法为Criteria对象设置查询条件,Order工具类的方法设置排序方式,Projections工具类的方法进行统计和分组。
  3. 使用Criteria对象的list()方法进行查询并返回结果

Restrictions类的常用方法: 

方法名称
描述
Restrictions.eq等于
Restrictions.allEq使用Map,Key/Valu进行多个等于的比对
Restrictions.gt大于
Restrictions.ge大于等于
Restrictions.lt小于
Restrictions.le小于等于
Restrictions.between对应SQL的between
Restrictions.like对应SQL的like
Restrictions.in对应SQL的in
Restrictions.andand关系
Restrictions.oror关系
Restrictions.sqlRestrictionSQL限定查询

Order类的常用方法: 

方法名称
描述
Order.asc升序
Order.desc降序

Projections类的常用方法 

方法名称
描述
Projections.avg求平均值
Projections.count统计某属性的数量
Projections.countDistinct统计某属性不同值的数量
Projections.groupProperty指定某个属性为分组属性
Projections.max求最大值
Projections.min求最小值
Projections.projectionList创建一个ProjectionList对象
Projections.rowCount查询结果集中的记录条数
Projections.sum求某属性的合计

示例: 
   1: Session session = SessionFactory.getCurrentSession();
   2: User user = null;
   3: Transaction ts = session.beginTransaction();
   4: try {
   5:     Criteria criteria = session.createCriteria(User.class);
   6:     criteria.add(Restrictions.eq("name","ijse"));
   7:     user= (User) criteria.list().get(0);    
   8:     session.commit();
   9: } catch (HibernateException ex) {
  10:     ts.rollBack();
  11:     ex.printStackTrace();
  12: }
  13: System.out.println(user.getName());

QBE(Query By Example)查询方式

将一个对象的非空属性作为查询条件进行查询。

示例: 
   1: Session session = SessionFactory.getCurrentSession();
   2: User user = new User();
   3: user.setName("ijse");
   4: Transaction ts = session.beginTransaction();
   5: try {
   6:     Criteria criteria = session.createCriteria(User.class);
   7:     criteria.add(Example.create(user));
   8:     user= (User) criteria.list().get(0);    
   9:     session.commit();
  10: } catch (HibernateException ex) {
  11:     ts.rollBack();
  12:     ex.printStackTrace();
  13: }
  14: System.out.println(user.getName());

离线查询

离线查询就是建立一个DetachedCriteria对象,将查询的条件等指定好,然后在session.beginTransaction()后将这个对象传入。通常这个对象可以在表示层建立,然后传入业务层进行查询。

示例: 
   1: DetachedCriteria detachedCriteria = DetachedCriteria.forClass(User.class);
   2: detachedCriteria.add(Restrictions.eq("name","ijse");
   3:  
   4: Session session = SessionFactory.getCurrentSession();
   5: User user = new User();
   6: Transaction ts = session.beginTransaction();
   7: try {
   8:     Criteria criteria = detachedCriteria.getExecutableCriteria(session);
   9:     user= (User) criteria.list().get(0);    
  10:     session.commit();
  11: } catch (HibernateException ex) {
  12:     ts.rollBack();
  13:     ex.printStackTrace();
  14: }
  15: System.out.println(user.getName());

复合查询

复合查询就是在原有查询的基础上再进行查询,可以调用Criteria对象的createCriteria()方法在这个Criteria对象的基础上再进行查询。

示例: 
   1: Session session = SessionFactory.getCurrentSession();
   2: User user = new 
   3: User();
   4: Transaction ts = session.beginTransaction();
   5: try 
   6: {
   7:  Criteria criteria1 = 
   8: session.createCriteria(Room.class);
   9: Criteria 
  10: criteria2 =criterial1.createCriteria("User");
  11:  
  12: criteria2.add(Restrictions.eq("name",new String("ijse"));
  13:  
  14: user= (User) criteria.list().get(0); 
  15:  
  16: session.commit();
  17: } catch (HibernateException ex) {
  18:  
  19: ts.rollBack();
  20:  
  21: ex.printStackTrace();
  22: }
  23: System.out.println(user.getName());

分页查询

分页查询主要是要指定两个参数:从第几条数据开始,取多少条数据。可以通过调用Query或者Criteria对象的setFirstResult()和setMaxResults()方法分别进行设定。

示例: 
   1: Session session = SessionFactory.getCurrentSession();
   2: List userList = null;
   3: Transaction ts = session.beginTransaction();
   4: try {
   5:     Criteria criteria = session.createCriteria(User.class);
   6:     criteria.setFirstResult(0);//从第一个数据开始
   7:     criteria.setMaxResults(10);//取10条记录
   8:     userList = (List) criterial.list();   
   9:     session.commit();
  10: } catch (HibernateException ex) {
  11:     ts.rollBack();
  12:     ex.printStackTrace();
  13: }



版权声明:本文为he90227原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。