您的位置:首页 > 其它

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

2015-09-06 14:36 363 查看
投影查询

是指查询结果仅包含部分实体或实体的部分属性。投影是通过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);
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: