论文部分内容阅读
[摘要] 文中对Hibernate检索策略中内存浪费的原因进行了研究,提出了采用查询缓存和集合过滤的方法进行查询优化, 降低了访问数据库的频率且避免了在数据查询检索过程中加载不需要的Java对象,从而降低了的内存消耗。最后,通过查询网上购物系统中客户的定单记录试验验证了优化方式的有效性。
[关键词] Hibernate 查询缓存 集合过滤 客户 定单
在分层的软件架构中持久化层封装了所有数据访问细节,是对象-关系映射(ORM)的中间件,Hibernate是一种ORM中间件工具,它对JDBC API进行了封装,负责Java对象的持久化。Hibernate通过Session接口提供了基本的保存、更新、删除和查询,Session具有一个缓存,位于缓存中的对象处于持久化状态,它和数据库中的相关记录对应,Session能够在某些时间点按照缓存中持久化对象的属性变化来同步更新数据库。在Session的缓存中存放的是相互关联的对象图。在默认情况下,当Hibernate从数据库中加载Java对象时,会同时加载所有关联的Java对象,从而影响了系统的性能。本文以查询网上购物系统中的客户(Customer)和定单(Order)信息为例,介绍如何设置Hibernate的检索策略,以优化查询性能。
一、常用查询方法
设计两个数据库表, 表名为CUSTOMERS和ORDERS, 它们包含的基本字段及之间的关系如图1:
Hibernate查询客户和定单信息的步骤为:
1.运用反射机制,获得customer对象的类型Customer.class。
2.参考对象-关系映射元数据,了解到和Customer类对应的表为CUSTOMERS表,类Customer与类Order关联,类Order和ORDERS表对应,ORDERS表中外键CUSTOMER_ID参照CUSTOMERS表的主键ID。
3.根据映射信息,生成SQL语句:
select *from CUSTOMERS;
select *from ORDERS where CUSTOMERS_ID=1。
4.调用JDBC API,执行以上SQL语句。Hibernate在检索与Customer关联的Order对象时,使用默认的立即检索策略。这种检索策略存在三大不足:
(1)select语句的数目太多需要频繁地访问数据库,会影响检索性能。
(2)在应用逻辑只需要访问Customer对象,而不需要访问Order对象的场合,加载Order对象完全是多余的操作,这些多余的Order对象浪费了许多内存空间。
(3)假定这个Customer对象与500个Order对象关联,就会加载500个Order对象。在实际应用中往往只需要访问Orders集合中的部分Order对象.例如访问客户定单金额大于100的Order对象,此时调用customer.getOrders().iterator()方法会影响运行时性能.因为它会加载应用程序不需要访问的Order对象。
延迟检索策略能避免多余加载应用程序不需要访问的关联对象;但当采用延迟检索策略时,应用程序如果希望访问游离状态的代理类实例,必须保证它作持久化状态时已经被初始化。迫切左外连接检索策略则利用SQL的外连接查询功能能够减少select语句的数目;但缺点在于可能会加载应用程序不需要访问的对象,浪费许多内存空间,更杂的数据库表连接也会影响检索性能。
二、查询性能优化
Hibernate主要可从以下两方面来优化查询性能。
1.使用查询缓存降低访问数据库的频率,减少select语句的数目;对于经常使用的查询语句如果启用了查询缓存.当第一次执行查询语句时,Hibernate会把查询结果存放在第二级缓存中。以后再次执行该查询语句时.只需从缓存中获得查询结果从而提高查询性能。对查询语句启用查询缓存的步骤如下:
(1)配置第二级缓存,在Customer.hbm.xml和 Order.hbm.xml映射文件中分别为Customer类、Customer类的orders集合以及Order类设置第二级缓存,
Customer.hbm.xml设置第二级缓存代码: name=“orders”
>
Order.hbm.xml设置第二级缓存代码:
(2)在Hibernate的配置文件hibernate.properties中选用EHCache和设置查询缓存属性:
hibernate.cache.provider_class=net.sf.hibernate.cache.EhCacheProvi
Hibernate.cache.use_query_cache=ture
(3)对于希望启用查询援存的查询语句.调用接口Query的setCacheable()方法:
Query orderByMoneyQuery=session.createQuery(“from Order o where o.money>:money”);
orderByMoneyQuery.setInteger(“money”, money);
orderByMoneyQuery. setCacheable(true);
如果希望更加精粒度地控制查询援存,可以设置缓存区域.
orderByMoneyQuery.setCacheRegion(“orderQueries”);
Hibernate提供了三种和查询相关的缓存区域
①默认的查询缓存区域:net.sf. hibernate.cache.StandardQueryCache
②用户自定义的查询缓存区域:如“orderQueries”
③时间戳缓存区域: net.sf. hibernate.cache.UpdateTimestampCache
默认的查询缓存区域以及用户自定义的查询缓存区域部用于存放查询结果。而时间戳缓存区域存放了对与查询结果相关的表进行插入、更新或删除操作的时间戳。Hibernate通过时间戳缓存区域来判断被缓存的查询结果是否过期,它的运行过程如下:
在T1时刻执行查询语句,把查询结果存放在QueryCache域.该区域的时间戳为TI时刻。
在T2时刻对与查询结果相关的表进行插入、更新或删除操作。Hibernate把T2时刻存放在UpdateTimestampCache区域。
在T3时刻执行查询语句前,先比较QueryCache区域的时间戳和UpdateTimestampCache区域的时间戳.如果T2>T1,那么就丢弃原先存放在QueryCache区域的查询结果,重新到数据库中查询数据再把查询结果存放在QueryCache区域;如果T2<T1,直接从QueryCache区域获得查询结果。
[关键词] Hibernate 查询缓存 集合过滤 客户 定单
在分层的软件架构中持久化层封装了所有数据访问细节,是对象-关系映射(ORM)的中间件,Hibernate是一种ORM中间件工具,它对JDBC API进行了封装,负责Java对象的持久化。Hibernate通过Session接口提供了基本的保存、更新、删除和查询,Session具有一个缓存,位于缓存中的对象处于持久化状态,它和数据库中的相关记录对应,Session能够在某些时间点按照缓存中持久化对象的属性变化来同步更新数据库。在Session的缓存中存放的是相互关联的对象图。在默认情况下,当Hibernate从数据库中加载Java对象时,会同时加载所有关联的Java对象,从而影响了系统的性能。本文以查询网上购物系统中的客户(Customer)和定单(Order)信息为例,介绍如何设置Hibernate的检索策略,以优化查询性能。
一、常用查询方法
设计两个数据库表, 表名为CUSTOMERS和ORDERS, 它们包含的基本字段及之间的关系如图1:
Hibernate查询客户和定单信息的步骤为:
1.运用反射机制,获得customer对象的类型Customer.class。
2.参考对象-关系映射元数据,了解到和Customer类对应的表为CUSTOMERS表,类Customer与类Order关联,类Order和ORDERS表对应,ORDERS表中外键CUSTOMER_ID参照CUSTOMERS表的主键ID。
3.根据映射信息,生成SQL语句:
select *from CUSTOMERS;
select *from ORDERS where CUSTOMERS_ID=1。
4.调用JDBC API,执行以上SQL语句。Hibernate在检索与Customer关联的Order对象时,使用默认的立即检索策略。这种检索策略存在三大不足:
(1)select语句的数目太多需要频繁地访问数据库,会影响检索性能。
(2)在应用逻辑只需要访问Customer对象,而不需要访问Order对象的场合,加载Order对象完全是多余的操作,这些多余的Order对象浪费了许多内存空间。
(3)假定这个Customer对象与500个Order对象关联,就会加载500个Order对象。在实际应用中往往只需要访问Orders集合中的部分Order对象.例如访问客户定单金额大于100的Order对象,此时调用customer.getOrders().iterator()方法会影响运行时性能.因为它会加载应用程序不需要访问的Order对象。
延迟检索策略能避免多余加载应用程序不需要访问的关联对象;但当采用延迟检索策略时,应用程序如果希望访问游离状态的代理类实例,必须保证它作持久化状态时已经被初始化。迫切左外连接检索策略则利用SQL的外连接查询功能能够减少select语句的数目;但缺点在于可能会加载应用程序不需要访问的对象,浪费许多内存空间,更杂的数据库表连接也会影响检索性能。
二、查询性能优化
Hibernate主要可从以下两方面来优化查询性能。
1.使用查询缓存降低访问数据库的频率,减少select语句的数目;对于经常使用的查询语句如果启用了查询缓存.当第一次执行查询语句时,Hibernate会把查询结果存放在第二级缓存中。以后再次执行该查询语句时.只需从缓存中获得查询结果从而提高查询性能。对查询语句启用查询缓存的步骤如下:
(1)配置第二级缓存,在Customer.hbm.xml和 Order.hbm.xml映射文件中分别为Customer类、Customer类的orders集合以及Order类设置第二级缓存,
Customer.hbm.xml设置第二级缓存代码:
>
Order.hbm.xml设置第二级缓存代码:
(2)在Hibernate的配置文件hibernate.properties中选用EHCache和设置查询缓存属性:
hibernate.cache.provider_class=net.sf.hibernate.cache.EhCacheProvi
Hibernate.cache.use_query_cache=ture
(3)对于希望启用查询援存的查询语句.调用接口Query的setCacheable()方法:
Query orderByMoneyQuery=session.createQuery(“from Order o where o.money>:money”);
orderByMoneyQuery.setInteger(“money”, money);
orderByMoneyQuery. setCacheable(true);
如果希望更加精粒度地控制查询援存,可以设置缓存区域.
orderByMoneyQuery.setCacheRegion(“orderQueries”);
Hibernate提供了三种和查询相关的缓存区域
①默认的查询缓存区域:net.sf. hibernate.cache.StandardQueryCache
②用户自定义的查询缓存区域:如“orderQueries”
③时间戳缓存区域: net.sf. hibernate.cache.UpdateTimestampCache
默认的查询缓存区域以及用户自定义的查询缓存区域部用于存放查询结果。而时间戳缓存区域存放了对与查询结果相关的表进行插入、更新或删除操作的时间戳。Hibernate通过时间戳缓存区域来判断被缓存的查询结果是否过期,它的运行过程如下:
在T1时刻执行查询语句,把查询结果存放在QueryCache域.该区域的时间戳为TI时刻。
在T2时刻对与查询结果相关的表进行插入、更新或删除操作。Hibernate把T2时刻存放在UpdateTimestampCache区域。
在T3时刻执行查询语句前,先比较QueryCache区域的时间戳和UpdateTimestampCache区域的时间戳.如果T2>T1,那么就丢弃原先存放在QueryCache区域的查询结果,重新到数据库中查询数据再把查询结果存放在QueryCache区域;如果T2<T1,直接从QueryCache区域获得查询结果。