Hibernate one-to-one 的N+1问题分析及其解决方法

转载 2013年12月04日 10:51:01

什么是N+1问题呢?



我们举一个例子来说明这个问题。
还是以 husband vs wife(夫:妻) 模型为例。
他们是一对一(one-to-one)的关系。并假设HUSBAND表为主表,WIFE表为从表。

CreateTables.sql

[java] view plaincopy
  1. #  
  2. # husband TABLE  
  3. #  
  4. CREATE TABLE HUSBAND (  
  5. ID CHAR(32) NOT NULL,  
  6. NAME CHAR(32) NOT NULL,  
  7. PRIMARY KEY(id)  
  8. )  
  9.   
  10. #  
  11. # wife TABLE  
  12. #  
  13. CREATE TABLE WIFE (  
  14. ID CHAR(32) NOT NULL,  
  15. NAME CHAR(32) NOT NULL,  
  16. HUSBAND_ID CHAR(32) NOT NULL,  
  17. PRIMARY KEY(id),  
  18. FOREIGN KEY(HUSBAND_ID) REFERENCE HUSBAND(ID)  
  19. )  


WIFE.HUSBAND_ID是一个外键,引用HUSBAND.ID。

假设在
Husband.hbm.xml里
定义与Wife的one-to-one关系。如下:
[java] view plaincopy
  1.     <one-to-one   
  2.           name="wife"  
  3.           cascade="all"  
  4.           class="mypackage.Wife"  
  5.           property-ref="husbandId"  >  
  6.       </one-to-one>  

如果我们使用HQL或Criteria查询时,例如:

FROM Husband h WHERE h.name = :name

或与其他表作联结查询时,比如:
FROM Husband h, Family f WHERE h.name = :name AND f.hid = h.id

之类的查询时,如果查询出的结果中存在N条数据,我们通过查看Hibernate打印出来的SQL语句,会发现Hibernate共向数据库发送了N+1条SQL查询。

为什么有这个问题呢?由于Husband表中未定义与Wife的关系(关系),所以Hibernate在查询时,Husband并不知道与它对应的Wife信息,所以Hibernate只有把Husband查询出来之后,再调用一次类似以下的查询,
SELECT * FROM WIFE WHERE HUSBAND_ID=?
把Wife信息查询出来,然后设置到Husband对象中加以关联。

所以如果存在N条数据,Hibernate会对每一条数据调用上面的SQL查询。从而一共会查询N+1次。

这就是one-to-one 的N+1问题。N+1问题造成大量SQL语句的执行,往往会引起严重的性能问题。

为了解决one-to-one 的N+1问题,笔者作了大量的测试,也查询了很多资料。
其中的测试包括使用fetch join等很多资料加以介绍的,结果one-to-one的情况,fetch join并不起效;另外,也尝试了
<one-to-one fetch="join" constrained="true" lazy="false" .../>
的定义形式,同样不行。


one-to-one 的N+1问题的解决方法


方法一:重新定义表结构,把关联字段放在主表一方。

然后在主表一方用many-to-one关联从表。

这种方法比较直观,也是最容易想到的方法。如下:
表HUSBAND定义:

[java] view plaincopy
  1. CREATE TABLE HUSBAND (  
  2. ID CHAR(32) NOT NULL,  
  3. NAME CHAR(32) NOT NULL,  
  4. WIFE_ID CHAR(32) NOT NULL,  
  5. PRIMARY KEY(id),  
  6. FOREIGN KEY(WIFE_ID) REFERENCE WIFE(ID)  
  7. )  

Husband.hbm.xml
[java] view plaincopy
  1.     <many-to-one   
  2.           name="wife" column="WIFE_ID"   
  3.           not-null="false"   
  4.           cascade="all"  
  5.           class="mypackage.Wife" >  
  6.       </many-to-one>  

方法二:表的结构定义不变。使用hibernate formula方程式。
方法如下:
Husband.hbm.xml
[java] view plaincopy
  1.     <many-to-one   
  2.           name="wife"  
  3.           not-null="false"   
  4.           cascade="all"  
  5.           class="mypackage.Wife" >  
  6.             <formula>(select w.ID from WIFE w where w.HUSBAND_ID = ID)</formula>  
  7.       </many-to-one>  


解说:
<formula>(select w.ID from WIFE w where w.HUSBAND_ID = ID)</formula>
该formula告诉HIBERNATE怎么与让Husband与Wife关联。

这样查询时,只会向数据库发送一条数据。
但是,如果需要从Husband对象存取Wife对象 [调用Husband.getWife()方法] 时:
List <Husband> list = query.list();
list.get(0).getWife();

Hibernate会动态向数据库发送一条查询数据。所以第2种方法,若要在页面上同时显示多条主表Husband与从表Wife的混合数据时,显然也会发生N+1问题。
但若只是显示多条Husband数据时,只发送一条SQL语句。

hibernate注解版关联映射Many-to-One/Many-to-Many等&异常处理

链接:http://blog.csdn.net/superdog007/article/details/8534443 属性介绍: 1.多对一: span style="font-size:...
  • xn_28
  • xn_28
  • 2017年03月15日 16:12
  • 1722

Hibernate中1+N问题以及解决方法

1. Hibernate中的1+N问题描述           在多对一关系中,当我们需要查询多的一方对应的表的记录时,可以用一条sql语句就能完成操作。然而,在多的一方的实体类中的@Many...
  • eson_15
  • eson_15
  • 2016年05月05日 13:38
  • 4753

Hibernate @OneToOne懒加载实现解决方案

在hibernate注解(三)中,我提高过一对一(@OneToOne)懒加载失效的问题。虽然给出了解决方法,但并没有给出完整的解决方案。今天我专门针对该问题进行讨论。至于懒加载失效的原因,在之前的文章...
  • wangpeng047
  • wangpeng047
  • 2014年02月25日 17:16
  • 11518

Android中导入工程出现Project has no default.properties file! Edit the project properties to set one.的解决方法

1、到其他工程里把这个default.properties文件拷贝过来直接用,没有关系,可以用的,都是一样的啦~          (这时候如果发现工程还是有错误的话就把工程重新导入一下,一般可以解...
  • nei504293736
  • nei504293736
  • 2011年12月09日 23:38
  • 551

开机提示:one of your disks needs to be checked解决方法

开机提示:one of your disks needs to be checked解决方法  笔记本启动时,连续2天出现了上面的问题,并有时会出现蓝屏现象。在撰写毕业论文的关键时刻,如果出点什么纰漏...
  • sunhuaqiang1
  • sunhuaqiang1
  • 2017年03月01日 08:40
  • 44364

more than one device/emulator问题解决方法

第一次使用adb工具,出现了问题。把解决办法发出来,希望能帮助到需要的人。 打开命令行界面,输入 adb shell,结果没有进入设备控制台,报错了,error:more than one devi...
  • chunxiao123ouc
  • chunxiao123ouc
  • 2016年03月03日 16:38
  • 429

hibernate 的many to one 的问题IllegalArgumentException occurred while calling setter of hibernatePOJO

package com.oyth.model; public class Book { private int BookID; private String BookName; pri...
  • xiaotaohong66
  • xiaotaohong66
  • 2013年08月10日 11:32
  • 7616

Hibernate One to Many 迟延加载分析

One to Many   1: Oneto Many,默认是采用延迟加载的(lazy=true),因为很多情况下,当我们获取到One的一方后,Many的一方并非立即需要的,当我们经常只需要One...
  • irelandken
  • irelandken
  • 2011年12月08日 15:41
  • 4765

windows Sun One asp 不支持父路径的解决方法.txt

  • 2013年04月26日 11:07
  • 215B
  • 下载

Android unspecified' depends on one or more Android Libraries but is a jar 的解决方法

1 错误描述引入一个第三方库作为module的时候遇到下面的报错: unspecified’ depends on one or more Android Libraries but is a j...
  • fuchaosz
  • fuchaosz
  • 2016年05月05日 10:27
  • 3379
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Hibernate one-to-one 的N+1问题分析及其解决方法
举报原因:
原因补充:

(最多只允许输入30个字)