hibernate N+1问题

Hibernate N+1 问题及解决办法sql

问题出现的缘由:数据库

Hibernate 中常会用到 set , bag 等集合表示 1 对多的关系,在获取实体的时候就能根据关系将关联的对象或者对象集取出,还能够设定 cacade 进行关联更新和删除。这不得不说 hibernate 的 orm 作得很好,很贴近 oo的使用习惯了。缓存

可是对数据库访问仍是必须考虑性能问题的,在设定了 1 对多这种关系以后, 查询就会出现传说中的 n+1 问题。性能

一对多: 在一方,查找获得了 n 个对象,那么又须要将 n 个对象关联的集合取出,因而原本的一条 sql 查询变成了 n+1 条;fetch

多对一: 在多方,查询获得了 m 个对象,那么也会将 m 个对象对应的 1 方的对象取出, 也变成了 m+1 ;spa

解决问题的方法:hibernate

      一、 使用 fetch 抓取, Hibernate 抓取策略分为单端代理和集合代理的抓取策略。代理

Hibernate 抓取策略 ( 单端代理的抓取策略 ) orm

   保持默认也就是以下 :对象

    <many-to-one name="clazz" cascade="save-update" fetch="select" />

    fetch="select" 就是另外发送一条 select 语句抓取当前对象关联实体或者集合设置 fetch="join"

     <many-to-one name="clazz" cascade="save-update" fetch="join"/>

Hibernate 会经过 select 语句使用外链接来加载器关联实体活集合此时 lazy 会失效

       Hibernate 抓取策略 ( 集合代理的抓取策略 ) 

            保持默认( fetch="select" )也就是以下 :

        <set name="students" inverse="true">

                 <key column="clazz"/>

                 <one-to-many class="com.june.hibernate.Student"/>

             </set>

             1)fetch="select" 会另外发出一条语句查询集合

             2) 设置 fetch="join" 采用外链接集合的 lazy 失效

             3) 这只 fetch="subselect" 另外发出一条 select 语句抓取前面查询到的全部的实体对象的关联集合 fetch只对 HQL 查询产生影响其余的则不会

       二、 使用 map 直接搜索须要的列

如:产品 product 和产品分类 product_category 两张表,多对一关系。查询产品列表时

select new Map(p.id as id, p.name as name, p.category.name as categoryName) from Product p

对数据库访问仍是必须考虑性能问题的, 在设定了1 对多这种关系以后, 查询就会出现传说中的n +1 问题。 
1 )1 对多,在1 方,查找获得了n 个对象, 那么又须要将n 个对象关联的集合取出,因而原本的一条sql查询变成了n +1 条 
2)多对1 ,在多方,查询获得了m个对象,那么也会将m个对象对应的1 方的对象取出, 也变成了m+1

怎么解决n +1 问题? 
1 )lazy=true, hibernate3开始已经默认是lazy=true了;lazy=true时不会马上查询关联对象,只有当须要关联对象(访问其属性,非id字段)时才会发生查询动做。 

2)二级缓存, 在对象更新,删除,添加相对于查询要少得多时, 二级缓存的应用将不怕n +1 问题,由于即便第一次查询很慢,以后直接缓存命中也是很快的。 
不一样解决方法,不一样的思路,第二条却恰好又利用了n +1 。

3) 固然你也能够设定fetch=join(annotation : @ManyToOne() @Fetch(FetchMode.JOIN))

相关文章
相关标签/搜索