1.使用dynamic-insert和dynamic-update
当需要更新或是插入部分数据时,hibernate默认户更新全部字段,若是目标表的字段特别多,将会对性能产生影响,因此此时可以设置dynamic-insert和dynamic-update
实例:
<class name="com.example.A" table="a" dynamic-update="true"></class>
2.延迟加载
当面对一对多等关系时,若是需要在查询1方时查询出关联的多方,则这种关联很方便,若是只是要使用1方的部分属性,那么查询时查询出关联到多方就会带来不必要的性能开销。此时使用延迟加载使程序的性能得到优化。延迟加载只有在session没有关闭的情况下,去获取多对应的数据集合时才会去动态的加载。所以在hibernate3中默认使用的是延迟加载。
如,若是没有使用延迟加载。
session的load方法会读取关联的数据。
session的load方法可以利用持久化对象实现延迟加载。但是get方法不能。
3.0网上的版本有3种形式实现延迟加载:
1)、通过<class>标签的lazy属性设置为true(默认),激活持久化对象的延迟加载。否则关闭延迟加载。
如:
<hibernate-mapping>
<class name="" table="" lazy="true">
</class>
</hibernate-mapping>
这时
session.load(Category.class,new Integer(12));
tx.commit();这时不会去读取数据库,只用使用对象的属性时才会去查询数据库(在session内)
使用session.load的方法获取的并不是一个真正的持久化对象,而是一个代理对象。
代理对象包含目标对象的属性和方法。真正的对象包含在代理对象的handler.target属性中。
为了能生成代理对象,hibernate要求所有持久化对象都要有公开的构造方法。该类不能声明为final类型的。且不能有声明final的方法。
代理对象在仅仅需要得到某个对象的引用(不需要获取该对象的所有属性)时非常有用。如
Category category = (Category)session.load(Category.class.new Integer(1));
Product product = new Product();
product.setCategory(category);
session.save(product);
tx.commit();
此时load方法并没有查询数据库,所以上面非常有用,若是load换成get方法,则先会根据主键查询出对象。
product保存时并不需要知道category的其他属性,只需要知道主键即可。
集合对象的延迟加载
在面对一对多或是多对多等关联时,对Set或是List不必要查询时,可以设置延迟加载。
如:
<class name="com.Category" table="category" lazy="true">//此处的lazy表示该对象使用延迟加载
...
<set name="products" cascade="save-update" inverse="true" lazy="true">
<key column="category_id"></key>
<one-to-many class="com.Product"/>
</set>
</class>
//对上面进行解释
cascade表示当对Category对象进行添加或是更改时,同时对关联的Product集合进行操作。
inverse=true表示,将控制权交给多方进行控制。即插入时先插入1方,再插入多方大的数据,数据库的插入就会避免update语句的产生了。
lazy=true表示在查询category时,不会查询set集合。
若是关闭set处的延迟加载
sql语句会先查询category,然后再通过category_id查询product集合。
设置lazy="extra"
这样即使调用集合的size(),isEmpty()等方法也不会去查询集合元素。
属性的延迟加载
属性的延迟加载使用于当某些持久化类包含BLOB,CLOB等字段时,而查询该持久化类又不需要使用该字段。此时可以考虑使用属性的持久化。
使用方式为<property name="" type="" lazy="true">
注意:属性持久化对性能提升可能不是很大,所以开发中很少使用。
解决LazyInitalizationException。
方法一,在关闭session前,调用Hibernate.initialize(category)//该方法会强制category加载关联的懒加载对象。
如:
Hibernate.initalize(category);
tx.commit();
category.getProduct()是可以调用的。
方法二,使用OpenSessionInview的设计模式。写一个Servlet的过滤器即可实现。
集合对象的抓取策略
适用于1对多或是多对多的关联查询中。
设置抓取策略可以通过持久化对象的映射文件中,或是HQL,或是Criteria。
Hibernate提供了4种抓取策略:
1)、查询抓取:hibernate底层先通过SQL语句查询持久话对象,然后再通过SQL语句查询关联的持久化对象集合。如果没有显示禁止懒加载,会在调用关联结合的时候再去查询。这也形成了N+1的查询。
2)、子查询,先通过SQL查询持久化对象,然后然后通过另一个子查询sql语句查询关联的对象。就是select中还有select。
3)、链接抓取、使用外联结抓取当前对象与关联的集合对象。
4)、批量抓取、首先获取主键或是外键的列表。然后根据列表获取一批对象或是集合
通过抓取策略结合延迟加载可以设置查询语句的执行时机。如果未启动延迟加载,会再加载持久化对象时立即加载关联的持久化对象和集合。即执行抓取策略相关的查询语句。
若是启动了延迟加载,会分布查询所需要查询的数据。
查询抓取
查询抓取首先查询当前的持久化对象,然后根据延迟加载设置判断立即查询还是延迟查询被关联的对象。
Hibernate通过fetch设置抓取策略
如
<set name="products" cascade="save-update" inverse="true" fetch="select">
<key column = "category_id"></key>
<one-to-many class="Product"/>
</set>
执行时,先查询当前对象,然后只有再调用set集合时才会执行select的进一步查询。
是2条SQL语句。
如果上面设置lazy="false",则也会执行2条sql语句,只是会立即执行。
使用映射文件设置抓取策略后仍然可以使用HQL或是Criteria重置抓取策略
如:
Query q = session.createQuery("select c from Category c where inner join fetch c.products where c.id=?");
此时sql语句会
select 类别的字段,产品的字段 from category,product where category.id = producct.category_id
子查询抓取
设置子查询时需要在持久对象的映射文件中配置。如
<set name="products" cascade="save-update" inverse="true" fetch="subselect">
<key column = "category_id"></key>
<one-to-many class="Product"/>
</set>
则查询时先查询category对象,然后使用
select product字段属性 from product表 where product.category_id in (select id from category)
链接抓取(只有这个对HQL语句无效)
设置链接抓取后在hibernate底层不会使用多长查询,而只需要通过一条sql语句就可以将对象与关联的对集合对象查询出来。设置join链接后不会对使用HQL生效。只对使用session.get,criteria.list方式生效。
设置链接抓取时,请使用fetch="join"。
sql语句会表现成:
select 类别字段,产品字段 from 类别表,产品表 where 类别表.id=产品表.类别ID and 类别id=?
批量抓取:
使用batch-size="5"进行设置,这样做hibernate会分批进行抓取。若是一共一百条记录会进行抓取20次。
sql语句如下:
select 类别字段 from 类别表
select 产品表字段 from 产品表 where 产品.类别ID in(?,?,?)会先获取5个对象。
Hibernate的N+1问题
当使用hibernate的iterator方法时,若是返回N个持久话对象会需要N+1次查询。
因为hibernate使用了缓存的机制,
所以首次查询持久化对象时,如iterator方法时,会先查询出所有持久化对象的ID,然后再通过ID去数据库里查询对应的持久化数据信息。若是第二次查询时就可以命中对象。
如果通过主键去map里查询没有命中,则会去数据库里查询。
如果iterator总是不能命中数据,那么会打打的影响hiberante的性能,此时可以考虑list方法。
如果大多数情况下命中缓存则会大大提升hiberante的性能。
所以要用辩证的眼光看待这个问题。
分享到:
相关推荐
《Hibernate性能优化》 在Java应用开发中,Hibernate作为一个强大的对象关系映射(ORM)框架,极大地简化了数据库操作。然而,如果不进行适当的优化,它可能会成为系统性能的瓶颈。以下是一些关于Hibernate性能优化...
### Hibernate性能优化研究 #### 一、引言 随着企业级应用的发展,高效的数据持久化技术成为了提升系统性能的关键因素之一。Hibernate作为一种流行的面向Java环境的对象关系映射(Object-Relational Mapping,简称...
### Hibernate性能优化方案详解 #### 一、引言 Hibernate作为Java领域中广泛使用的对象关系映射(ORM)框架,其高效性和灵活性受到众多开发者的青睐。然而,不当的设计和配置往往会导致性能瓶颈,严重影响应用程序...
"Hibernate性能优化共9页.pdf.zip" 这个文件标题表明了内容专注于Hibernate框架的性能优化,暗示我们将探讨如何提升使用Hibernate进行数据库操作时的效率。通常,性能优化涉及减少延迟、提高吞吐量、降低资源消耗等...
Hibernate 性能优化 在 Hibernate 中,性能优化是非常重要的,因为它直接影响着应用程序的效率和可扩展性。在本文中,我们将讨论两个常见的性能优化问题:批量处理和 1+n 问题,并提供相应的解决方法。 问题 1:...
本文将深入探讨Hibernate性能优化中的一个重要概念——一级缓存,并结合给出的压缩包文件“hibernate_cache_level1”,来详细解析一级缓存的工作原理及其优化策略。 一级缓存是Hibernate内置的一种缓存机制,它存在...
以下是对《hibernate性能优化[参考].pdf》内容的详细解读: 1. **数据库优化**: - **物理硬件优化**:关注磁盘的IO性能,因为数据库读写频繁,磁盘的寻道能力直接影响数据访问速度。 - **MySQL配置优化**:通过...
### Hibernate 性能优化 #### 一、引言 Hibernate 是一款非常强大的对象关系映射(ORM)框架,它能够简化 Java 应用程序与数据库之间的交互过程。然而,对于初次接触 Hibernate 的开发者来说,可能会遇到性能方面...
二级缓存是Hibernate性能优化的重要手段,通过合理配置和使用,可以显著减少数据库访问,提高系统响应速度。但同时,需要注意缓存的副作用,如数据一致性、并发控制等问题。在实际应用中,需要结合业务场景和性能...
在进行大型项目开发时,性能优化是至关重要的,特别是对于基于SSH(Struts、Spring、Hibernate)这样的企业级框架的应用。SSH性能优化主要是针对Struts的MVC处理、Spring的依赖注入以及Hibernate的对象关系映射进行...
### Hibernate性能调优知识...综上所述,Hibernate性能优化涉及多个层面,包括但不限于关联管理、集合类型选择、继承关系配置以及缓存策略等。合理配置这些选项能够显著提高应用程序的性能,并且减少不必要的资源消耗。
【标签】:hibernate, 性能优化 【正文】: 1. **数据库设计调整**: - **降低关联的复杂性**:减少多对多关联,避免过度嵌套的对象关系。 - **避免联合主键**:联合主键可能导致额外的性能损失,尝试使用单独的...
的效率低于直接JDBC存取,然而,在经过比较好的性能优化之后,Hibernate的性能还是让人相当满意的, 特别是应用二级缓存之后,甚至可以获得比较不使用缓存的JDBC更好的性能,下面介绍一些通常的 Hibernate的优化策略...