首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 网站开发 > Web前端 >

Hibernate高级运用:性能优化策略

2012-09-19 
Hibernate高级应用:性能优化策略1.一级缓存(session里面的实体对象,存放在内存中)?get/load/list/iterate

Hibernate高级应用:性能优化策略

1.一级缓存(session里面的实体对象,存放在内存中)

?get/load/list/iterate可以将对象放入到一级缓存中

List操作不会利用一级缓存

?get/load/iterate可以利用一级缓存

?flush方法将改变后的同对象持久化到数据库中

2.二级缓存

即SessionFactory级别的缓存。默认的情况下是打开的。这是一个全局缓存策略。它可以对对象的数据进行全局缓存。

一级缓存  二级缓存 缓存的是实体对象

缓存的key是ID,缓存的value是实体对象

3.查询缓存(慎用)

即对查询的结果集进行缓存处理,以便下次相同条件相同HQL的情况下可以直接从缓存中获取数据。

查询缓存的作用,是对list操作的查询结果集进行缓存!

缓存的是普通结果集

缓存的key是HQL中的语句与参数,缓存的value则:

(1)如果查询的结果为普通结果集,则缓存这些结果集

(2)如果查询的结果为实体对象,则缓存实体对象的ID列表

用查询缓存的时候,二级缓存也要启用,防止发出多条语句

我们使用list操作的时候,如果启用了查询缓存,hibernate将根据当前查询的HQL语句(及其参数值)计算出一个缓存的key值;查询结果集,将作为缓存的value值(但如果查询结果集是一个对象结果集的话,其缓存的value值是对象的ID集合,而不是对象集合本身)。

<o:p> </o:p>

可以在hibernate配置文件中添加:

<property name="hibernate.cache.use_query_cache">true</property><o:p></o:p>

以便打开查询缓存。

<o:p> </o:p>

查询缓存,对对象查询,将缓存其ID列表;对普通查询,将缓存整个数据集合。所以,对于对象查询,需要配合二级缓存来使用。

<o:p> </o:p>

在打开了查询缓存之后,需要注意,调用query.list()操作之前,必须显式调用query.setCachable(true)来标识某个查询使用缓存。

4.批量抓取

(1)抓取策略,有一个对象 ,即如何获取关联的策略。

(2)什么叫批量抓取:有一批对象,想得到这批对对象的关联

(3)在many-to-one/one-to-many中设置:fetch(在hbm.xml语句中配置)

Fetch="select" 查询抓取,通过第二条语句查询关联(这是默认值)

Fetch="join"  连接抓取,在加载的同时通过一条外连接已经把关联的对象加载

上来了,所以设置的lazy配置失效

Fetch="join"  对于批量抓取的时候是无效的

当Fetch="select"可以定义批量抓取策略,在对方的class映射文件中配置batch-size

即可

 连接抓取(Join fetching) - Hibernate通过 在SELECT语句使用OUTER JOIN(外连接)来 获得对象的关联实例或者关联集合。 连接抓取策略可以被定义在<many-to-one/>或集合(如<set/>)标签上。这种抓取策略,对load/get操作有效。

·         如在Student的<many-to-one/>标签上设置fetch=”join”,当我们load/get一个Student的时候,其classes属性的值,将通过一个outter join连接查询来获取

·         或在Classes类的<set />标签上设置fetch=”join”,当我们load/get一个Classes类的实例的时候,其集合数据,也是通过一个outter join连接查询来抓取

·        查询抓取(Select fetching) - 另外发送一条 SELECT 语句抓取当前对象的关联实体或集合。除非你显式的指定lazy="false"禁止 延迟抓取(lazy fetching),否则只有当你真正访问关联关系的时候,才会执行第二条select语句。 这种抓取策略,设置方法为:fetch=”select”;

·         如在set标签上设置fetch=”select”,下面的查询:List list = session.createQuery("from Classes cls where id in (1,22)").list();将产生如下结果:

Hibernate: select classes0_.id as id7_, classes0_.name as name7_ from T_Classes classes0_ where classes0_.id in (1 , 22)<o:p></o:p>

<o:p> </o:p>

Hibernate: select students0_.classesid as classesid1_, students0_.id as id1_, students0_.id as id8_0_, students0_.name as name8_0_, students0_.sex as sex8_0_, students0_.classesid as classesid8_0_ from T_Student students0_ where students0_.classesid=?<o:p></o:p>

<o:p> </o:p>

Hibernate: select students0_.classesid as classesid1_, students0_.id as id1_, students0_.id as id8_0_, students0_.name as name8_0_, students0_.sex as sex8_0_, students0_.classesid as classesid8_0_ from T_Student students0_ where students0_.classesid=?<o:p></o:p>

可见,总共发出:第一,查询Classes的数据;第二,因为查询结果集中有两个Classes对象,所以针对每个对象,都发出了一个查询语句以便查询其students集合的数据。<o:p></o:p>

·       <o:p> </o:p>

·         子查询抓取(Subselect fetching) - 另外发送一条SELECT 语句抓取在前面查询到(或者抓取到)的所有实体对象的关联集合。除非你显式的指定lazy="false" 禁止延迟抓取(lazy fetching),否则只有当你真正访问关联关系的时候,才会执行第二条select语句。 设置方法是:fetch=”subselect”,它只能被设置在集合映射的属性上。

·         如在set标签上设置fetch=”sebselect”,下面的查询:List list = session.createQuery("from Classes cls where id in (1,22)").list();在list对象中,将包含两个Classes对象的实例,假设其集合上配置lazy=”false”,我们立刻就能看到hibernate的subselect抓取策略是:

以下是hibernate生成的SQL语句:<o:p></o:p>

Hibernate: select classes0_.id as id7_, classes0_.name as name7_ from T_Classes classes0_ where classes0_.id in (1 , 22)<o:p></o:p>

<o:p> </o:p>

?悲观锁和乐观锁

两个人同时修改用一条数据时,就会才产生数据不一致

这是我们需要用乐观锁来解决这个问题!

悲观锁:锁定一条记录,当修改成功后,对方才能修改(一直等待)

在实体bean中设置

Person p=(Person)session.get(Person.class, 1,LockOptions.UPGRADE);

缺点:当遇到多个线程的时候,会发送死锁,效率也不高(不建议使用)

乐观锁(建议使用):通过版本号约束hibernate是否更新,避免了数据更新的丢失,在实体类中加属性版本号:int versionNumber ,在对应的映射文件中添加<version name="versionNumber"></version>

5.批量更新/保存

向数据库中插入1万条数据,如何提高效率?

对于在Mysql数据库中加入<property name="hibernate.connection.url">(oracle数据库中则不需要加入)

jdbc:mysql://localhost/hibernate?rewriteBatchedStatements=true</property>

//<property name="hibernate.jdbc.batch_size">25</property>

 

 

热点排行