Criteria Query的使用
Criteria 查询表达式
Criteria 本身只是一个查询容器,具体的查询条件需要通过Criteria.add方法加到Criteria实例中。
示例1:
Criteria criteria = session.createCriteria(TPerson.class); criteria.add(Restrictions.eq("name", "oham")); criteria.add(Restrictions.eq("address", "earth")); criteria.list();
执行sql:
select this_.id as id0_0_, this_.name as name0_0_, this_.address as address0_0_, this_.tel as tel0_0_, this_.zipcode as zipcode0_0_ from t_person this_ where this_.name=? and this_.address=?
注意, 1)鄙人使用的Hibernate版本为4.1.4.Final,示例1的中Restrictions是先前版本的Expression的替代,在4.1.4.Final中,Expression已被标记为过期。
2)针对SQL语法,Restrictions提供了对应的查询机制,可以去看看:http://docs.jboss.org/hibernate/orm/4.1/javadocs/
3)Restriction中的各个方法的属性名参数是指POJO中的属性名,非真实数据库表的字段名。
Example类的使用
Example实现了Criteria接口,所以也可以用作Criteria的查询条件。Example的作用是,根据已有的对象,查找属性与之相符的其他对象。一般用于组合查询,如,界面上提供若干查询选项,然后根据用户所选返回符合条件的结果。
示例2:
Criteria criteria = session.createCriteria(TPerson.class); Example example; example = Example.create(examplePerson); /** * 默认的情况下,Hibernate会过滤掉示例对象的Null值属性,可以通过调用 * excludeNone/excludeZeroes方法进行调整,或则通过excludeProperty将 * 某个属性排除在外。 * 1.excludeNone —— 不过滤Null值的属性 * 2.excludeZeroes —— 过滤值为0 的属性 * 3.请测测example.excludeNone与example.excludeZeroes,若两者调用,貌似 * 只用后者起作用。。。 */ // example.excludeZeroes(); // example.excludeNone(); // example.excludeProperty("address"); criteria.add(example); criteria.list();
执行上述的代码的sql:
select this_.id as id0_0_, this_.name as name0_0_, this_.address as address0_0_, this_.tel as tel0_0_, this_.zipcode as zipcode0_0_, this_.age as age0_0_ from t_person this_ where ( this_.name=? and this_.address=? and this_.age=? )
Criteria复合查询
现在引入一个一对多的场景:
执行下面的代码,打印出所有的person以及对应的skill:
Criteria criteria = session.createCriteria(TPerson.class); List<TPerson> personList = criteria.list(); for(TPerson person : personList) { System.out.println(person.getName()); Set<TSkill> set = person.getSkills(); for(TSkill skill : set) { System.out.println("\t\t" + skill.getName()); } }
结果:
Hibernate: select this_.id as id0_0_, this_.name as name0_0_, this_.address as address0_0_, this_.tel as tel0_0_, this_.zipcode as zipcode0_0_, this_.age as age0_0_ from t_person this_ Hibernate: select skills0_.pid as pid0_1_, skills0_.id as id1_, skills0_.id as id1_0_, skills0_.name as name1_0_, skills0_.pid as pid1_0_ from t_skill skills0_ where skills0_.pid=? Oham meditation kill
如果现在想查出所有具有kill技能的person,可以使用复合查询:
Criteria criteria = session.createCriteria(TPerson.class); //在原有的查询基础上,针对TPerson对象的skills属性构造新的查询过滤条件 Criteria addCriteria = criteria.createCriteria("skills"); addCriteria.add(Restrictions.like("name", "%kill%")); List<TPerson> personList = criteria.list(); for(TPerson person : personList) { System.out.println(person.getName()); Set<TSkill> set = person.getSkills(); for(TSkill skill : set) { System.out.println("\t\t" + skill.getName()); } }
Hibernate会在运行期构造以下的sql:
select this_.id as id0_1_, this_.name as name0_1_, this_.address as address0_1_, this_.tel as tel0_1_, this_.zipcode as zipcode0_1_, this_.age as age0_1_, tskill1_.id as id1_0_, tskill1_.name as name1_0_, tskill1_.pid as pid1_0_ from t_person this_ inner join t_skill tskill1_ on this_.id=tskill1_.pid where tskill1_.name like ?
DetachedCriteria
criteria对象生于session,所以其生命周期位于session之内,即虽不同生,必同死。。。这样就很大程度限制了Criteria的重用,对于相同的查询条件,在不同的session实例里需要再实例一个Criteria。
DetachedCriteria是可以脱离Session实例而独立存在的,于是我们可以使用其将某些通用的Criteria查询条件进行抽离,然后使用的时候将其再与当前的session实例绑定。
示例3:
//生成detachedCriteria的实例 DetachedCriteria detachedCriteria = DetachedCriteria.forClass(TPerson.class); //detachedCriteria的用法与criteria基本类似 DetachedCriteria addDetachedCriteria = detachedCriteria.createCriteria("skills"); addDetachedCriteria.add(Restrictions.like("name", "%kill%")); SessionFactory factory = HibernateLocalUtil.getSessionFactory(); Session session = factory.openSession(); //调用getExecutableCriteria与当前的session实例绑定 Criteria criteria = addDetachedCriteria.getExecutableCriteria(session); List<TPerson> personList = criteria.list(); for(TPerson person : personList) { System.out.println(person.getName()); Set<TSkill> set = person.getSkills(); for(TSkill skill : set) { System.out.println("\t\t" + skill.getName()); } } session.close();
DetachedCriteria也可用于子查询,现在想查询大于平均年龄的所有person。
示例4:
DetachedCriteria avgAge = DetachedCriteria.forClass(TPerson.class); avgAge.setProjection(Projections.avg("age")); Criteria criteria = session.createCriteria(TPerson.class); criteria.add(Subqueries.propertyGt("age", avgAge)); List<TPerson> list = criteria.list();
生成执行 sql:
select this_.id as id0_0_, this_.name as name0_0_, this_.address as address0_0_, this_.tel as tel0_0_, this_.zipcode as zipcode0_0_, this_.age as age0_0_ from t_person this_ where this_.age > ( select avg(this_.age) as y0_ from t_person this_ )
Criteria的其他特性辑录
——限定返回结果范围:
Criteria criteria = session.createCriteria(TPerson.class); //从100条结果开始的20条记录 criteria.setFirstResult(100); criteria.setMaxResults(20);
——排序:
//按名字(顺序)和地址(逆序)排序 criteria.addOrder(Order.asc("name")); criteria.addOrder(Order.desc("address"));
——分组与统计:
//对年龄age进行分组 criteria.setProjection(Projections.groupProperty("age"));
生成sql:
select this_.age as y0_ from t_person this_ group by this_.age
对于多条件组合的分组、统计功能,可以借助ProjectionList,现在统计各个年龄的person数量,
示例5:
ProjectionList pList = Projections.projectionList(); pList.add(Projections.groupProperty("age")); pList.add(Projections.rowCount()); criteria.setProjection(pList); criteria.list();
生成sql:
select this_.age as y0_, count(*) as y1_ from t_person this_ group by this_.age
HQL(Hibernate Query Language)
Hibernate提供的一套类SQL的查询语言。
具体语法: [select / update / delete ...] [from ...] [where ... ] [group by ...] [having ...] [order by ...],用起来与SQL十分类似,但注意好像HQL没有insert之用。
注意“
1.若查询或操作一个实体表的数据,from 后面跟的是实体类名,可以采用全路径类名,特别是同名不同包的情况。
2.HQL字句本身大小写无关,但其中出现的类名和属性名需要区分大小写。
3.若查询的目标实体存在继承关系的判定,例如 TUser 有两个子类TSystemUser和TAdmin,分别做了实体映射, 那么 from TUser 这条HQL返回的记录将包含这两个子类的所有数据,而包含的字段是与父类公有的那些。
4.from java.lang.Object 这句将返回数据库所有表的数据。
以下示例基于如下表关系:
用法举例:
1.获取某个实体的几个属性时可以这样:select u.name, u.age from TUser as u,而此时,list结果集中每个条目是个Object[]类型,不是实体类型,依次包含了所获取的各个属性数据。可以让其返回实体类对象,这样就行了:select new TUser(u.id, u.name) from TUser u,前提是TUser必须有这个构造函数(不好用。。。)。
下面是测试代码:
String hql1 = "from TUser"; String hql2 = "select u.id, u.name from TUser u"; String hql3 = "select new TUser(u.id, u.name) from TUser u"; // List list = session.createQuery(hql1).list(); // List list = session.createQuery(hql2).list(); List list = session.createQuery(hql3).list(); Iterator iterator = list.iterator(); while(iterator.hasNext()) { //for hql and hql3 TUser u = (TUser)iterator.next(); System.out.println(u.getName()); // for hql2 /*Object[] results = (Object[])iterator.next(); System.out.println(results[1]);*/ }
2.动态的参数绑定:
(1)使用query接口方法:
String hql = "from TUser u where u.name = ?"; Query query = session.createQuery(hql); query.setString(0, "lulu"); List list = query.list();
(2)使用占位符:
String hql = "from TUser u where u.name = :name"; Query query = session.createQuery(hql); query.setParameter("name", "Lulu");
说明动态的参数绑定机制可以使得查询语法与具体的参数值相互独立,这样,对于参数不同,SQL语法相同的查询操作,数据库可以实施性能优化策略。同时避免了参数值对语法本身的影响,也就避免了SQL Injection。
3.HQL的引用查询,将HQL语句本身从代码中抽出,写在映射配置文件当中。
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="learnHibernate.bean"> <class name="TUser" table="t_user"> <id name="id" column="id" type="java.lang.Integer"> <generator class="native"/> </id> <property name="name" column="name" type="java.lang.String"/> </class> <query name="TUser.getByName"> <![CDATA[ from TUser u where u.name = :name ]]> </query> </hibernate-mapping>
然后代码中:
Query query = session.getNamedQuery("TUser.getByName"); query.setParameter("name", "Lulu");
4.HQL的联合查询,就是跟SQL的inner join ,left outter, right outer join, full join 差不多的。
注意的是:
1. 关键字fetch ,看示例代码:
String hql = "from TUser u join fetch u.addrs"; Query query = session.createQuery(hql); List list = query.list(); Iterator it = list.iterator(); while(it.hasNext()) { TUser u = (TUser)it.next(); System.out.print(u.getName() + "----"); System.out.println(u.getAddrs().size()); }
上述的HQL对应SQL为:
select ... from t_user U inner join t_address addr on uid=addr.uid
(其中因为on uid=addr.uid所描述的对应关系已在映射文件中指定,所以HQL无对应的表现)
这里的fetch表示查出address对象后立刻立刻填充到对应的TUser对象的address集合属性中。若不加fetch,则list当中每个条目是个Object[],其中Object[]包含了一个TUser对象和对应的一个TAddress对象,运行代码:
String hql = "from TUser u join u.addrs"; Query query = session.createQuery(hql); List list = query.list(); Iterator it = list.iterator(); while(it.hasNext()) { Object[] arr = (Object[])it.next(); for(int i=0; i< arr.length; i++) { if(arr[i] instanceof TUser) { System.out.println( ((TUser)arr[i]).getName() ); }else if(arr[i] instanceof TAddress) { System.out.println( "---" + ((TAddress)arr[i]).getAddr() ); } } }
输出结果:
Hibernate: select tuser0_.id as id0_0_, addrs1_.id as id1_1_, tuser0_.name as name0_0_, addrs1_.uid as uid1_1_, addrs1_.addr as addr1_1_ from t_user tuser0_ inner join t_address addrs1_ on tuser0_.id=addrs1_.uid Cancan ---Mars Oham ---Earth Lulu ---Moon Lulu ---Earth Maomao ---Venus
2.fetch 只对inner join 和 left outer join 有效,这是因为想right outer join,full join之类,作为关联对象可能为空,因此Hibernate无法通过fecth 进行集合填充操作。
数据加载方式
Hibernate中支持以下的数据加载方式:
1.即时加载(Immediate Loading)—— 当实体加载完毕,立即加载其关联的数据。
2.延迟加载(Lazy Loading)—— 实体加载时,其关联数据不是立刻获取,而是当关联数据第一次被访问时再进行读取。
3.预先加载(Eager Loading)—— 实体及其关联对象同时读取,这与即时加载类似,不过实体及关联数据是通过一条SQL语句(基于外连接[outer join])同时读取。
4.批量加载(Batch Loading)—— 对于即时加载和延迟加载,可以采用批量加载方式进行性能上的优化。
举例说明,这里引入TUser及其地址的一对多关联。
即时加载,TUser映射中描述关联关系的配置段:
<set name="addrs" table="t_address" cascade="none" lazy="false"> <key column="uid" /> <one-to-many class="TAddress" /> </set>注意lazy=“false”。运行代码:
Criteria criteria = session.createCriteria(TUser.class); criteria.add(Restrictions.eq("name", "lulu")); List list = criteria.list();输出结果:
Hibernate: select this_.id as id0_0_, this_.name as name0_0_ from t_user this_ where this_.name=? Hibernate: select addrs0_.uid as uid0_1_, addrs0_.id as id1_, addrs0_.id as id1_0_, addrs0_.uid as uid1_0_, addrs0_.addr as addr1_0_ from t_address addrs0_ where addrs0_.uid=?可以看出即时加载的时候,当加载关联主题TUser的时候,Hibernate会自动读取其关联的数据并完成关联属性的填充。
延迟加载,有时我们只想取得TUser的信息,无需取得其对应的地址信息,即使用延迟加载,相应的关联关系配置段:
<set name="addrs" table="t_address" lazy="true"> <key column="uid" /> <one-to-many class="TAddress" /> </set>把lazy设置为“true”就行了。执行代码:
Criteria criteria = session.createCriteria(TUser.class); criteria.add(Restrictions.eq("name", "lulu")); List list = criteria.list();输出结果:
Hibernate: select this_.id as id0_0_, this_.name as name0_0_ from t_user this_ where this_.name=?可以看出此时只加载了TUser的数据,没有相应的Address信息,若加上读取Address的代码:
相关推荐
**Hibernate使用——入门** Hibernate 是一个强大的开源对象关系映射(ORM)框架,它简化了Java应用程序与数据库之间的交互。这篇博文将引导你入门Hibernate,理解其基本概念和使用方法。 **1. Hibernate概述** ...
在Java开发中,Hibernate是一个非常重要的对象关系映射(ORM)框架,它简化了数据库操作,使得开发者可以使用面向对象的方式来处理数据。本教程将深入探讨如何使用Hibernate来实现一个简单的课程管理系统,涵盖多对...
通过将Java对象与数据库表之间的映射关系进行抽象,Hibernate允许开发者用面向对象的方式处理数据,从而减少了对SQL的直接依赖。 ### Hibernate 4简介 Hibernate 4是Hibernate框架的一个重要版本,它带来了许多改进...
标题"Hibernate自动创建表结构示例--Oracle"表明我们将使用Hibernate在Oracle数据库中自动生成表结构,这是通过Hibernate的`hibernate.hbm2ddl.auto`配置属性实现的。这个属性可以设置为"create"、"update"、...
本篇将详细介绍如何在Oracle数据库环境下,使用MyEclipse进行Hibernate逆向工程的配置和应用。 首先,确保你的开发环境中已经安装了MyEclipse并配置了Oracle数据库连接。在MyEclipse中,打开Database Explorer视图...
总结来说,"struts2+hibernate整合例子——新闻管理系统"是一个典型的Java Web应用示例,展示了如何利用Struts2的MVC模式和Hibernate的ORM能力,实现对新闻数据的CRUD操作及高级查询。这个系统可能包含了Action类、...
这些查询语言提供了面向对象的方式来检索数据,比传统的 SQL 更加灵活和强大。 1. **HQL**:类似于 SQL,但它是面向对象的。例如,以下 HQL 查询语句用于获取所有学生: ```java Session session = ...
【标题】"安卓Android源码——Hibernate4.zip" 提供的是关于在Android平台上使用Hibernate4框架的源代码示例。Hibernate4是一个流行的Java对象关系映射(ORM)工具,它允许开发者将数据库操作与Java对象模型相结合,...
在使用Hibernate进行数据操作时,主要有两种方式:HQL(Hibernate Query Language)和Criteria API。HQL是一种面向对象的查询语言,而Criteria API提供了更动态的查询构建方式。 例如,使用HQL查询所有用户: ```...
在"jpa之使用hibernate示例代码"中,我们可能会涉及以下关键知识点: 1. **实体类(Entity)**:在JPA中,实体类是Java类,代表数据库中的表。它需要使用`@Entity`注解标记,并且通常有一个主键字段,用`@Id`注解...
`chapter5`关注的是Hibernate的查询语言——HQL(Hibernate Query Language)和Criteria API。HQL是一种面向对象的查询语言,允许开发者用类名和属性名来编写查询,极大地提高了代码的可读性。Criteria API提供了一...
这个项目可能包括了前端界面、后端业务逻辑以及数据存储层的处理,使用了Struts作为MVC框架,Hibernate作为对象关系映射(ORM)工具,这些都是Java开发中的关键组件。 Struts是Apache软件基金会的Jakarta项目下的一...
- **二级缓存**:除了Session缓存之外,Hibernate还支持跨Session的缓存机制——二级缓存。通过配置二级缓存插件,可以实现跨Session的数据共享,进一步提高系统的性能。 #### 综合示例解析 以上述部分示例代码为...
本文介绍了在使用Hibernate框架查询Oracle数据库时遇到的一个常见问题——char类型字段映射为单个字符,并提供了三种解决方案。首先,可以通过调整Hibernate的映射方式,使用`addScalar`方法显式指定字段的类型;...
Spring与Hibernate的整合进一步简化了数据访问层的编写,通过Spring的数据访问抽象,如JdbcTemplate或HibernateTemplate,可以实现更优雅的数据库操作。 这个实战教程的压缩包文件包含了多个部分,可能代表教程的...
Hibernate提供了一种灵活的查询方式——Criteria API和HQL(Hibernate Query Language),它们都支持分页查询。在这些查询中,我们可以通过设置`FirstResult`和`MaxResults`参数来实现分页。`FirstResult`表示从结果...
【标题】"自己动手模仿Hibernate写数据库框架"揭示了本次讨论的核心内容——尝试构建一个类似于Hibernate的数据库操作框架。Hibernate是一个流行的Java ORM(对象关系映射)框架,它简化了数据库与Java对象之间的...
Hibernate提供了自己的查询语言——Hibernate Query Language(HQL),类似于SQL,但更面向对象。此外,还可以使用Criteria API进行动态查询。 6. ** Criteria API** Criteria API是一种更高级的查询方式,允许...