首页 > 代码库 > Hibernate N+1问题及解决办法

Hibernate N+1问题及解决办法

Hibernate N+1 问题及解决办法

问题出现的原因:

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

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

一对多: 在一方,查找得到了 n 个对象,那么又需要将 n 个对象关联的集合取出,于是本来的一条 sql 查询变成了 n+1 条;

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

解决问题的方法:

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

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

   保持默认也就是如下 :

    <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 查询产生影响其他的则不会

       2、 使用 map 直接搜索需要的列

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

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