精通Hibernate——报表查询、技巧以及优化

投影查询
是指查询结果仅包含部分实体或实体的部分属性。投影是通过select关键字来实现的。以下Hql会检索出Customer及关联的Order对象

from Customer c join c.orders o where o.orderName like 'T%';

如果希望查询结果中只包含Customer对象

select c from Customer c join c.orders o where o.orderName like 'T%';

或者

select c.id,c.name from Customer c joinwhere o.orderName like 'T%';

以上Hql对应Sql:

select c.id,c.name from customer c inner join orders o on c.id = o.customer_id where o.order_name like 'T%';

当select语句仅仅选择查询持久化类的部分属性时,Hibernate返回的查询结果为关系数据,而非持久化对象例如:

from Customer c inner join c.orders o group by c.age;
select c.id,c.name,o.id,o.order_number,o.customer_id from Customer c inner join c.orders c group by c.age;

以上两条hql查询语句对应的sql语句相同,区别在于前者返回的是Customer和Orders持久化对象,他们位于session的缓存中,Session会保证他们的唯一性。后者返回的是关系数据,他们不会占用Session的缓存,只要应用程序中没有任何变量引用这些数据,他们占用的内存就可以被jvm垃圾回收器回收。
对于第二种hql语句,可以定义一个JavaBean来保证查询结果中的数据,使应用程序仍旧按照面向对象的方式来访问查询结果:

select from new CustomerOrder(c.id,c.name,o.id,o.order_number,o.customer_id) from Customer c inner join c.orders o group by o.age;

高级查询技巧
集合过滤
对于已经加载的Customer持久化对象,假定他的orders集合由于使用了懒加载而没有被初始化,那么只要调用customer.getOrdersd().interator()方法,Hibernate就会初始化Orders集合,这种方式存在的两大不足:
1、假定这个Customer对象与1000个Orders关联,就会加载1000个Orders对象,在实际应用中往往只需要orders集合中部分Order对象
2、不能对orders集合中Order对象进行排序
解放办法有二:
1、Hql

List resulst = session.createQuery("from Order o where o.customer=:customer and o.price>100 order by o.price").setEntity("customer",customer).
list();

2、集合过滤

List result = session.createFilter(customer.getOrders(),"where this.price>100 order by this.price").list();
Iterator it = result.iterator();
while(it.hasNext()){
    Order order = (Order)it.next();
    ....
}

session.createFilter特点:
1.他返回Query类型的实例
2.他的第一个参数指定一个持久化对象的集合,这个集合是否已经被初始化并没有关系,这个集合是否已经被初始化并没有关系,但他所属的对象必须处于持久化状态。
3.他的第二个参数指定过滤条件,他由合法的hql组成
4.不管持久化对象的集合是否已经被初始化,Query的list方法都会执行sql查询
5.如果Customer对象的orders集合已经被初始化,为了保证Session的缓存中不会出现OID相同的对象,Query的list方法不会再创建Order对象,仅仅返回已经存在Order对象的引用
6.如果Customer对象的orders集合还没有被初始化,Query的list方法会创建相应的Order对象,但是不会初始化Customer的orders集合
查询性能的优化
1、降低数据库的访问频率,减少select语句的数目,实现手段包括:
1)使用迫切左外连接或迫切内连接检索策略
2)对延迟检索或立即检索策略设置批量检索数目
3)使用查询缓存
2、避免多余加载程序不需要的数据库访问,实现手段:
1)使用延迟加载策略
2)使用集合过滤
3、避免报表查询数据占用缓存。实现手段为利用投影查询功能
4、减少select语句中的字段,从而降低访问数据库的数据量。实现手段为利用Query的iterate()方法
iterate()方法
Query接口iterate方法和list方法都能执行sql查询,但是前者有时会有轻微性能提升

Query query1 = session.createQuery("from Customer c");
List result1 = query1.list();

Query query2 = session.createQuery("from Customer c where c.age < 30");
list result2 = query2.list();

以上会两次访问数据库进行查询,很明显第二次不需要再查询数据,第二次查询的结果可以在第一次查询的结果中获得,可以使用以下方式

Query query1 = session.createQuery("from Customer c");
List result1 = query1.list();

Query query2 = session.createQuery("from Customer c where c.age < 30");
Iterator result2 = query2.iterate();

Query接口的iterate方法首先检索ID字段,然后根据ID字段到Hibernate的一级缓存以及二级缓存中查找匹配的Customer对象,如果存在,就直接加入到查询结果中,否则执行额外的select语句,根据ID到数据中检索该兑现。
查询缓存
如果启用了查询缓存,当第一次执行查询时,Hibernate会把查询结果放在二级缓存中。以后再次查询语句时,只需要从缓存中获得查询结果,从而提高查询性能。
值得注意的是如果查询结果中包含实体,第二级缓存只存放实体OID,而对于投影查询,第二级缓存会存放所有的数据值,对于查询语句启用缓存步骤如下:
1、配置第二级缓存
2、在Hibernate的hibernate.properties配置文件中设置查询缓存属性

hibernate.cache.use_query_cache = true

3、配置了步骤2,Hibernate在执行时候仍然不会启用查询缓存,还需调用Query接口的setCacheable()方法

Query customerByAgeQuery = session.createQuery("from Customer c where c.age>:age");
customrByAgeQuery.setInteger("age",age);
customrByAgeQuery.setCacheable(true);
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值