131.报表查询
报表查询利用数据库执行有效的数据分组和聚集的能力。它们天生更为相关;它们并非始终返回实体。
HQL和JPA QL允许使用几个最常用于报表的SQL特性——虽然它们也用于其他目的。在报表查询中,给投影使用SELECT子句,给聚集使用GROUP BY和HAVING子句。
(1)利用统计函数投影
HQL识别的并在JPA QL中标准化的统计函数式count()、min()、max()、sum()和avg()。
特殊的COUNT(DISTINCT)函数忽略重复:
select count(distinct i.description) from Item i
(2)给统计结果分组
就像在SQL中一样,出现在HQL或者JPA QL中但在SELECT子句中的一个统计函数之外的任何属性或者别名,也必须出现杂GROUP BY子句中。
(3)用having限制分组
WHERE子句用来在行上执行限制的相关操作。HAVING子句在分组上执行限制。
管理SELECT和HAVING子句的规则一样:只有被分了组的属性才可能出现在统计函数之外。
(4)利用动态的实例化
一般用于报表查询的,字节组(tuple)特别不方便,因此HQL和JPA QL提供了SELECT NEW构造器嗲用。除了用这种技术动态创建新对象之外,也可以把它与聚集和分组组合起来使用。
如果用含有Long、Long和BigDecimal的构造器,定义一个称作为itemBidSummary的类,就可能用到下列查询:
select new ItemBidSummary(bid.item.id,count(id),avg(bid)))from Bid bid
where bid.item.successfulBid is null
group by bid.item.id
注意,此处必须编写一个完全限定的类名,带有包名,除非类已经被导入到HQL命名空间。这个方法是类型安全的,并且数据前一类可以轻松地对报表中值得特殊格式打印进行扩展。
(5)利用报表查询提示性能
报表查询导致被分配的内存的更快是否,因为对象没有被保存在持久化上下文高速缓存中,知道上下文关闭——执行报表之后,一旦它们没有被应用程序引用,可能就立即被当做垃圾收集起来。
132.利用子查询
子查询是内嵌在另一个查询中的查询,一般在SELECT、FROM或者WHERE子句中。
HQL和JPA QL支持WHERE中的子查询。FROM子句中的子查询不受HQL和JPA QL的支持(虽然规范把它们列为一项可能的未来扩展),因为这两种语言都没与传递闭包。查询的结果可能不是表格,因此不能在FROM子句中重新用于选择。SELECT子句中的子查询也不受查询语言的支持,但可以通过公式(formula)映射到属性。
(1)相关的和不相关的嵌套
from User u where 10<(
select count(i) from u.items i where i.successfulBid is not null
)
from Bid bid where bid.amount+1>=(
select max(b.amount) from bid b
)
(2)量词
如果一个子查询返回多行,它就是与量词(quantification)组合了。ANSI SQL、HQL和JPA QL定义了下列量词:
ALL——如果对子查询的结果中所有值的比较为真,表达式就取值为true。如果子查询结果的单个值没有通过比较测试,就取值为false。
ANY——如果对子查询的结果中有些(任何)值的比较为真,表达式就取值为true。如果子查询结果为空或者没有值满足比较,就取值为false。关键字SOME是ANY的同义词。
IN——这个二进制的比较操作符可以针对一个子查询的结果比较一系列值,并且如果在结果中找到所有值,则取值为true。
例如这个查询返回所有出价都小于100的货品:
from Item i where 100>all(select b.amount from i.bids b)
下一个查询返回所有其他的货品,即出价大于100的:
from Item i where 100<=any(select b.amount from i.bids b)
这个查询返回出价正好为100的货品:
from Item i where 100= some(select b.amount from i.bids b)
这个也一样:
from Item i where 100 in (select b.amount from i.bids b)
HQL对在元素或者集合的索引上操作的子查询支持快捷语法。
List result=session.createQuery("from Category c where :givenItem in elements(c.items)").setEntity("givenItem",item).list();
133.Criteria和Example API都只可在Hibernate中使用;Java Persistence没有标准化这些接口。
最简单的条件查询看起来像这样:
session.createCriteria(Item.class);
它获取Item类的所有持久化实例。这也称作条件查询的根实体(root entity)。
(1)应用限制
对于条件查询来说,你必须构建Criterion对象来表达约束。Restrictions类给内建的Criterion类型提供工厂方法。
session.createCriteria(User.class).add(Restrictions.eq("homeAddress.street","Foo"));
(2)创建比较表达式
所有一般的SQL(和HQL、JPA QL)比较操作符也可以通过Restrictions类使用:
Criterion restriction=Restrictions.between("amount",new BigDecimal(100),new BigDecimal(200));
三重逻辑操作符也可用;这个查询返回没有电子邮件地址的用户:
session.createCriteria(User.class).add(Restrictions.isNull("email"));
(3)字符串匹配
对于条件查询,通配符搜索可以使用与HQL和JPA QL相同的通配符符号(%和_),或者指定MatchMode。MatchMode是不用字符串操作来表达子字符串匹配的一种方便的方法。
得到之后的MatchMode是START、END、ANYWHERE和EXACT。
(4)组合表达和逻辑操作符
如果把多个Criterion实例添加到同一个Criteria实例,它们被联结起来应用(利用and)
(5)添加任意的SQL表达式
session.createCriteria(User.class).add(Restrictions.sqlRestriction("length{alias}.PASSWORD<?",5,Hibernate.INTEGER));
这个查询返回密码少于5个字符的所有User对象。
(6)编写子查询
条件查询中子查询是一个WHERE子句查询。就像在HQL、JPA QL和SQL中一样,子查询的结果可能包含单行或多行。
134.联结和动态抓取
(1)给限制联结关联
在Criteria API中表达联结有两种方法:因此你有两种给限制使用别名的方法。第一种是Criteria接口的createCriteria()方法。这个方法一般意味着你可以嵌套对createCriteria()的调用。这个方法一般意味着你可以嵌套对createCriteria()的调用:
Criteria itemCriteria=session.createCriteria(Item.class);
itemCriteria.add(
Restrictions.like("description","Foo",MatchMode.ANYWHERE)
);
用Criteria API表达内部联结的第二种方法是为被联结的实体分配一个别名:
session.createCriteria(Item.class).createAlias("bids","b")
.add(Restrictions.like("description","%Foo%"))
.add(Restrictions.gt("b,amount",new BigDecimal(99)));
(2)通过调节查询动态获取
在HQL和JPA QL中,你用join fetch操作即时填入一个集合,或者初始化一个被映射为延迟否则将被代理的对象。你可以用Criteria API完成同样的事:
session.createCriteria(Item.class).setFetchMode("bids",FetchMode.JOIN)
.add(Restrictions.like("description","%Foo%"));
并行即时抓取不止一个集合,会造成一个SQL笛卡尔积,它或许比两个单独的查询更慢。如果你给集合使用即时抓取,那么给限制分页结果集也在内存中完成。
可以在jieguoList中移除重复的引用,通过把它包装在LinkedHashSet中(常规的HashSet不保存查询结果的顺序)。在HQL和JPA QL中,也可以使用DISTINCT关键字;然而,在Criteria中,没有它的直接等加入。这就是ResultTransformer变得有用的地方。
(3)应用结果转换器
结果转换器可以被应用到查询结果,以便你可以用自己的过程而不是Hibernate的默认行为过滤或者封送结果。Hibernate的默认行为时你可以自己替换和(或定制的一组默认转换器)。
Criteria.ROOT_ENTITY是org.hibernate.transform.ResultTransformer接口的默认实现。前一个查询无论是否使用这个转换器设置都生成相同的结果。
135.投影和报表查询
(1)简单的投影列表
Criteria中的setProjection()方法,接受任何单个的被投影的属性,或者接受要包括在结果中的几个属性的的一个列表。
(2)统计和分组
一般的统计函数和分组选项在条件查询中也可以用。有一种简单的方法统计结果中的行数:
session.createCriteria(Item.class).setProjection(Projections.rowCount())
session.createCriteria(Bid.class).createAlias("bidder","u")
.setProjection(Projections.projectionList())
.add(Projections.groupProperty("u.id"))
.add(Projections.groupProperty("u.username").as("uname"))
.add(Projections.count("id"))
.add(Projections.avg("amount"))
)
.addOrder(Order.asc("uname"));
(3)利用SQL投影
SQL投影是被添加到生成的SQL SELECT子句的一个任意片段。
String sqlFragment="(select count(*) from ITEM i where i.ITEM_ID=ITEM_ID) as numOfItems";
session.createCriteria(Bid.class).createAlias("bidder","u")
.setProjection(Projections.projectionList()
.add(Projections.groupProperty("u.id"))
.add(Projections.groupProperty("u.username"))
.add(Projections.count("id"))
.add(Projections.avg("amount"))
.add(Projection.sqlProjection(
sqlFragment,
new String[]{"numOfItem"},
new Type[]{HIbernate.LONG})
));
136.按示例查询
public List findUsers(String firstname,String lastname)
{
Criteria crit=getSession().createCriteria(User.class);
if(firstname!=null)
{
crit.add(Restrictions.ilike("firstname",firstname,MatchMode.ANYWHERE));
}
if(lastname!=null)
{
crit.add(Restrictions.ilike("lastname",lastname,MatchMode.ANYWHERE));
}
crit.addOrder(Order.asc("username"));
return crit.list();
}
public List findUserByExample(User u) throws{
Example exampleUser=Example.create(u)
.ignoreCase()
.enableLike(MatchMode.ANYWHERE)
.excludeProperty("password") ;
return getSession().createCriteria(User.class).add(exampleUser).list();
}
137.利用原生的SQL查询
(1)自动结果集处理
利用Hibernate API执行SQL语句的最大好处在于,自动把表格式的结果集封送到业务对象中去。
List result=session.createSQLQuery("select * from CATEGORY").addEntity(Category.class).list();
(2)获取标量值
标量值可以是任何Hibernate值类型。
List result=session.createSQLQuery("select * from ITEM").list();
这个查询的result是Object[]的一个List,实际上是一张表。每个数组中的每个字段都是标量类型即字符串、数字或者时间戳。除了包装在一个Object[]中之外,结果与类似的简单JDBC查询结果完全一样。
如果没有用*投影每件东西,就要告诉Hibernate你想要从结果中返回哪些标量值:
session.createSQLQuery("select u.FIRSTNAME as fname from USER u").addScalar("fname");
addScalar()方法告诉Hibernate,你的fname SQL别名应该作为标量值返回,并且类型应该被自动推测。
(3)Java Persistence中的原生SQL
Java Persistence通过在EntityManager中用createNativeQuery()方法支持原生的SQL查询。原生的SQL查询可以返回实体实例、标量值或者两者的混合。然而,不同于Hibernate,Java Persistence中的API利用映射元数据来定义结果集处理。
138.过滤集合
集合过滤器——可以应用到持久化集合(或者数组)的一种特殊查询。它常用于进一步限制或者排序结果。
Hibernate集合过滤器不是在内存中执行的。此外,不要把过滤器应用到瞬时的集合或者查询结果。它们只能应用到当前被添加到Hibernate持久化上下文的一个实体实例引用的持久化集合。术语“过滤器”有点误导,因为过滤的结果是一个全新的不同集合,并没有接触到原始的集合。
139.高速缓存查询结果
高速缓存查询结果是一个完全不同的问题。查询结果高速缓存在默认情况下是禁用的,并且每一个HQL、JPA QL、SQL和Criteria查询都始终先命中数据库。
(1)启用查询结果高速缓存
查询高速缓存必须用Hibernate配置属性来启用:
hibernate.cache.use_query_cache=true
然而,单独这个设置对于Hibernate高速缓存查询结果还不够。默认情况下,所有的查询都始终忽略高速缓存。为了个特定的查询启用查询高速缓存(允许它的结果被添加到高速缓存,并允许从高速缓存中提取结果),那么使用org.hibernate.Query接口。
Query categoryByName=session.createQuery("from Category c where c.name=:name");
categoryByName.setString("name",categoryName);
categoryByName.setCacheable(true);
setCacheable()方法启用了结果高速缓存。它在Criteria API上也可用。如果想给javax.persistence.Query启用结果高速缓存,就使用setHint("org.hibernate.cacheable",true);
高速缓存实体的状态,是二级高速缓存区域auction.model.Category(结合持久化上下文)的责任。这类似于iterate()的查询策略,如前所述。换句话说,如果你查询实体,并决定启用高速缓存,就要确保你也给这些实体启用了常规的二级高速缓存。如果没有,可能在启用高速缓存之后,以更多的数据库命中而告终。
如果查询结果高速缓存在Hibernate中被启用,另一个始终需要的高速缓存区域也出现了:org.hibernate.cache.UpdateTimestampsCache。这是Hibernate内部使用的一个高速缓存区域。
Hibernate用时间戳区域来决定被高速缓存的查询结果集是否为失效的。当你重新执行一个启用了高速缓存的查询时,Hibernate就在时间戳高速缓存中查找对被查询的(几张)表所做的最近插入、更新、或者删除的时间戳。如果找到时间戳晚于高速缓存查询结果的时间戳,高速缓存结果就被丢弃,并产生一个新查询。
通常要把构成自然键的属性映射为Hibernate中的常规属性。可以在数据库级启用一个unique约束来表示这个键。
相关推荐
《黑马程序员_hibernate框架开发2016版讲义和笔记资料_day02》 本文将深入探讨2016年黑马程序员发布的Hibernate框架开发课程的第二天内容。Hibernate,一个强大的Java持久化框架,简化了数据库操作,为开发者提供了...
本学习笔记涵盖了Hibernate的基本概念、核心功能及实战应用,通过深入学习,开发者可以有效地将ORM理念应用于实际项目,提升数据库操作的效率和代码的可维护性。请阅读`hibernate学习笔记.pdf`以获取详细内容。
《Hibernate框架开发详解——以黑马程序员2016版讲义和笔记为引导》 Hibernate,作为Java领域中广泛使用的对象关系映射(ORM)框架,极大地简化了数据库操作,使得开发者可以更专注于业务逻辑而不是繁琐的数据访问...
### JavaEE学习实战笔记心得 #### JavaSE基础要点 - **环境配置**: - **JDK下载与安装**:确保下载与操作系统相匹配的JDK版本,完成安装。 - **环境变量设置**: - **JAVA_HOME**: 指向JDK的安装目录。 - **...
第2版的开发手册是理解Hibernate早期版本的基础,尽管较旧,但它仍然涵盖了许多至今仍然适用的基础知识。对比不同版本的开发手册,开发者可以了解到Hibernate的发展历程,理解新版本的变化,从而更好地适应框架的...
本资料集合了作者itherima在学习和使用Hibernate 5.0.7版本时的笔记、源码分析和实际操作案例,旨在帮助读者深入理解Hibernate的核心概念和实用技巧。 1. **基础知识篇** - Hibernate概述:介绍Hibernate的基本...
**JBPM3学习笔记** JBPM(Java Business Process Management)是一个开源的工作流管理系统,它提供了对业务流程的建模、部署、执行和监控的能力。在本文中,我们将深入探讨JBPM3的核心概念、功能和使用方法,以帮助...
### WebWork学习笔记知识点 #### 一、WebWork框架简介 - **定义**: WebWork是一个由OpenSymphony组织开发的MVC(Model-View-Controller)框架,专注于组件化和代码重用,适用于J2EE应用程序开发。 - **最新版本**:...
这份"springboot学习思维笔记"很可能是对SpringBoot核心概念、特性、以及如何进行有效学习的一系列整理和归纳,通常包括思维导图(xmind)形式的概览和详细的文本说明。 1. **SpringBoot基础知识** - **自动配置**...
《SpringBoot实战(第四版)》是一本专为SpringBoot初学者设计的高清教程,由丁雪丰翻译,提供清晰的目录结构,并且允许文本复制粘贴,方便学习和笔记整理。SpringBoot作为Java开发中的热门框架,因其简化配置、快速...
总的来说,这份"黑马程序员_struts2框架开发2016版讲义和笔记资料"是一个全面学习和掌握Struts2框架的宝贵资源,涵盖了从基础到实践的所有重要方面,对于提升Java EE开发者的技能水平大有裨益。通过系统学习,开发者...
- **《21天学通JavaScript(第2版)》** 和 **《JavaScript动态网页开发案例指导》** 则通过丰富的案例帮助读者快速掌握 JavaScript 的核心概念和技术。 通过以上资源的学习,无论是初学者还是有一定经验的开发者,...
这个项目采用ExtJs+struts2+hibernate+spring等技术栈实现了图书管理系统,适合中级开发者用来学习企业级应用的开发方法。 #### 二十四、java聊天程序 该聊天程序支持私聊、公聊、截图、文件传输等功能,是一份...
"SD0711_EJB_Note_All"这个文件名可能指的是一个完整的EJB 3.0教程或笔记集合,它可能会涵盖EJB 3.0的所有主要概念、API使用、实战案例和最佳实践。通过深入学习这个资料,你可以全面了解EJB 3.0,掌握企业级应用...