Hibernate 性能优化

Hibernate性能优化

为了进一步优化Hibernate的性能,可以使用延迟加载技术管理数据抓取策略进行缓存管理 等方面考虑来提高Hibernate的性能。

一、延迟加载

1延迟加载load)是Hibernate为提高程序执行效率而提供的一种机制,即只有真正使用该对象的数据时才会创建。

2、延迟加载的过程:通过代理(Proxy)机制来实现延迟加载。Hibernate从数据库获取某一个对象数据时、获取某一个对象的集合属性值时,或获取某一个对象所关联的另一个对象时,由于没有使用该对象的数据(除标识符外),Hibernate并不从数据库加载真正的数据,而只是为该对象创建一个代理对象来代表这个对象,这个对象上的所有属性都为默认值;只有在真正需要使用该对象的数据时才创建这个真正的对象,真正从数据库中加载它的数据。

3、类型:对象的延迟加载对象里的属性延迟加载集合延迟加载

4Hibernate中默认采用延迟加载的情况主要有以下几种:

1)当调用Session上的load()方法加载一个实体时,会采用延迟加载。

2)当Session加载某个实体时,会对这个实体中的集合属性值采用延迟加载。(one-to-many

3)当Session加载某个实体时,会对这个实体所单端关联(one-to-one,  many-to-one)的另一个实体对象采用延迟加载。

4)能够懒加载的对象都是被改写过的代理对象,当相关联的session没有关闭时,访问这些懒加载对象(代理对象)的属性(getIdgetClass除外)hibernate会初始化这些代理,或用Hibernate.initialize(proxy)来初始化代理对象;当相关联的session关闭后,再访问懒加载的对象将出现异常。

2、关闭延迟加载

1)在加载单个实体时,如果不需要延迟加载,就可以使用sessionget()方法。

2)当Session加载某个实体时,不需要对这个实体中的集合属性值延迟加载,而是要立即加载。这时可以在映射文件中针对这个集合属性的配置元素(<set><bag><list>…)添加属性lazy=“false”

3)当Session加载某个实体时,不需要对这个实体所单端关联的另一个实体对象延迟加载,就可以在映射文件中对这个单端关联的配置元素(<one-to-one>,<many-to-one>)添加属性lazy=“false”

    注意:one-to-one不能有constrained=true

二、抓取策略

HQL语句中使用抓取连接查询,通过写一条left join fetch语句把相关联的两个实体的数据一次性从数据库中加载上来。这样可以在特定情况下(同时需要使用到这两个实体的数据)减少SQL的数量来提高查询效率。

通过配置抓取策略来直接影响sessionget()load()方法的查询效果。

1.单端关联<many-to-one><one-to_one>上的抓取策略。

   可以给单端关联的映射元素添加fetch属性。fetch属性有2个可选值

  1select:作为默认值,它的策略是当需要使用到关联对象的数据时,另外单独发送一条select语句抓取当前对象的关联对象的数据。即延迟加载。

  2join:它的策略是在同一条select语句使用连接来获得对象的数据和它关联对象的数据,此时关联对象的延迟加载失效。

2.集合属性上的抓取策略

在集合属性的映射元素上可以添加fetch属性,它有3个可选值。

 1select:作为默认值,它的策略是当需要使用所关联集合的数据时,另外单独发送一条select语句抓取当前对象的关联集合,即延迟加载。

2join:在同一条select语句使用连接来获得对方的关联集合。此时关联集合上的lazy会失效。

3subselect:另外发送一条查询语句(或子查询语句)抓取在前面查询到的所有实体对象的关联集合。这个策略对HQL的查询也起作用。

3、加载选择

1)当fetchjoin时,执行左外连接,这个时候,在加载Customer时,Customer所对应的Order值全部被加载到缓存中,如果Order中没有大数据,这个策略是一个不错的选择。

2)当fetchsubselect时,针对in有效,如果为select时,fromCustomer where id in(1,2,3),hibernate会把ID取出来,逐一的去取Order的值,效率比较低。这个时候subselect效率比较高,不管in里含有多少数据,在查询Order是,只会发出一条sql语句。把<set>集合中batch-size设置为一个比较合适的数值时也相当于fetchsubselect,你可以根据项目的因素来选择发出sql语句的次数。

HQL总是忽略映射文件中设置的预先抓取策略,即在HQL中使用预先抓取时,必须显示指明fetch关键字。然而不同的是,QBC则不会忽略映射文件中的预先抓取策略。

4、关联级别检索策略

在映射文件中,用<.set>元素来配置一对多关联关系,<.set>元素有lazyfetch属性

1Lazy:主要决定orders集合被初始化的时机,即到底是在加载Customer对象时就被初始化,还是在程序访问orders集合时被初始化

2fetch:取值为“select”或“subselect”是,决定初始化orders的查询语句的形式;若取值为“join”,则决定orders集合被初始化的时机。

若把fetch设置为“join”,lazy属性将被忽略。

三、缓存管理

1、基本概念

  1)、缓存(cache)在java应用程序中是一组内存中的集合实例。它保存着永久性存储源(如硬盘上的文件或者数据库)中数据的备份,它的读写速度比读写硬盘的速度快。应用程序在运行时直接读写缓存中的数据,只在某些特定时刻安装缓存中的数据来同伴更新数据存储源。如果缓存中存放的数据量非常大,也会用硬盘作为缓存的物理介质。

   2)、缓存的作用就是降低应用程序直接读写永久性数据存储源的频率,从而增强应用的运行性能。

(3)、缓存的实现不仅需要作为物理介质的硬件(内存),同时还需要用于管理缓存并发访问和过期等策略的软件。

2缓存范围分类

缓存的范围决定了缓存的生命周期及其可以被谁访问。缓存的范围分为以下三类:

(1)事务范围:缓存只能被当前事务访问。缓存的生命周期依赖于事务的生命周期,当事务结束时,缓存也就结束生命周期。在此范围下,缓存的介质是内存。

(2)进程范围:缓存被进程内的所有事务共享。这些事务有可能是并发访问缓存,因此必须对缓存采取必要的事务隔离机制。

(3)集群范围:在集群环境中,缓存被一个机器或者多个机器的进程共享。缓存的数据被复制到集群环境中的每个进程节点,进程间通过远程通信来保证缓存中的数据一致性。对于大多数应用来说,应该慎用集群范围的缓存,因为访问的速度并不一定比直接访问数据库数据的速度快很多。

3.缓存的并发访问策略

在进程范围或集群范围的缓存,会出现并发问题。因此可以设置4中类型的并发访问策略,每一种策略对应一种事务隔离级别。事务的隔离级别越高,并发性能就越低。

(1)事务型(Transactional)策略

2)读写型(Read-Write)策略

(3)非严格读写型(Nonstrict-read-write)策略

(4)只读型(Read-only)策略

4.Hibernate中的缓存

(1)第一级别的缓存是Session级别的缓存,它是属于事务范围的缓存。

(2)第二级别的缓存是SessionFactory级别的缓存,它是属于进程范围范围的缓存,这一级别的缓存可以进行配置和更改,并且可以动态加载和卸载。

3Hibernate还为查询结果提供一个查询缓存,它依赖于二级缓存。

一级缓存的管理

1Session级别的缓存由hibernate自动管理。当应用程序调用SessionCRUD方法及调用查询接口的list()iterate()等方法时,如果在Session缓存中还不存在相应的对象,Hibernate就会把改对象加入到Session缓存中。如果在Session缓存中已经存在这个对象,就不需要再去数据库加载而是直接使用缓存中的这个对象,可以减少访问数据库的频率,提高程序的运行效率。当Hibernate清理缓存时(默认是提交事务的时候),Hibernate会根据缓存中对象的状态来同步数据库中的数据状态,在关闭Session时,会清空Session缓存中的所有对象。

2)一级缓存不能控制缓存的数量,所以要注意大批量操作数据时可能造成内存溢出;

可以用

evict(Objectobj):从缓存中清除指定的持久化对象。

clear():清空缓存中所有持久化对象。

flush():进行清理缓存(此时缓存中的数据并不丢失)的操作,让缓存和数据库同步执行一些列sql语句,但不提交事务。

commit():先调用flush()方法,然后提交事务.则意味着提交事务意味着对数据库操作永久保存下来。

⑤可以写一个for循环,Session可以批量插入上万条数据。如下面的代码:

            For(int i=0;i<10000;i++){

                     Session.save(object);

}

注意:这样写的代码会使一万个对象的缓存全部存在于内存中,这样做加大了内存的压力。所以应该定期清理session的缓存。

当做批量插入或批量更新时,必须通过经常调用Sessionflush()以及稍后调用clear()来控制一级缓存的大小,这样内存才能保证足够的空间。

二级缓存的管理

二级缓存是SessionFactory级别的缓存,它的使用过程如下:

1)执行条件查询的时候,发出“select* from table_name where …”这样的SQL语句查询数据库,一次获得所有的数据对象。

2)把获得的所有数据对象根据ID放入到二级缓存中。

3)当Hibernate根据ID访问数据对象时,首先从Session缓存中查;查不到,如果配置了二级缓存,那么从二级缓存中查;还没查到,再查询数据库,把结果按照ID放入到二级缓存。

4)删除、更新和增加数据的时候,同时会更新到二级缓存中。

Hibernate的二级缓存策略是针对ID查询的缓存策略,对于调节查询则毫无作用。为此,hibernate提高了单独针对条件查询的查询缓存。

缓存存放数据

适合存放到二级缓存中的数据有:

1)很少被修改的数据。

2)不是很重要的数据,允许出现偶尔的并发的数据。

3)很多系统模块都要用到

4)不是私有的数据,是共享的

不适合放在二级缓存中:

财务数据 安全性的数据也就是不想让别人看到的数据和特别重要的数据

常用的缓存插件

Hibernate的二级缓存是一个插件。几种常用的缓存插件;EHCacheOSCacheSwarmCacheJBossCache

5.二级缓存配置

配置二级缓存时,考虑的问题是决定哪些持久化类需要使用二级缓存,缓存的并发访问策略选择哪一种,然后再根据这些情况来选择合适的缓存插件,编辑该插件的配置文件。

步骤:

1、 拷贝ehcache-1.5.0.jar到当前工程的lib目录下

2、 开启二级缓存

3、 要指定缓存的供应商

4、 指定使用二级缓存的类

方法一:在使用类的*.html配置

选择需要使用二级缓存的持久化类,设置它的二级缓存的并发访问策略,<class>元素的cache子元素表明Hibernate会缓存对象的简单属性,但不会缓存集合属性,若希望缓存集合属性中的元素,必须在<.set>元素中加入<cache>子元素。

方法二:在hibernte.xml文件中配置(建议)

<!—指定使用二级缓存的类放在maping下面-->

<!—配置类级别的二级缓存-->

<.class-cacheclass=”cn.itcast.c3p0.Customer” usage=”read-write”/>

<class-cacheclass=”cn.itcast.c3p0.Order” usage=”read-write”/>

<!—配置集合级别的二级缓存-->

<collection-cachecollection=”cn.itcast.c3p0.Customer.orders” usage=”read=write”/>

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值