SSH框架中N+1查询问题与解决方案

news/2024/7/7 10:09:20

在Session的缓存中存放的是相互关联的对象图。默认情况下,当Hibernate从数据库中加载Customer对象时,会同时加载所有关联的Order对象。以Customer和Order类为例,假定ORDERS表的CUSTOMER_ID外键允许为null,图1列出了CUSTOMERS表和ORDERS表中的记录。

 

n+1查询

以下Session的find()方法用于到数据库中检索所有的Customer对象:

List customerLists=session.find("from Customer as c");

运行以上find()方法时,Hibernate将先查询CUSTOMERS表中所有的记录,然后根据每条记录的ID,到ORDERS表中查询有参照关系的记录,Hibernate将依次执行以下select语句:

select * from CUSTOMERS; 
select * from ORDERS where CUSTOMER_ID=1;
select * from ORDERS where CUSTOMER_ID=2;
select * from ORDERS where CUSTOMER_ID=3;
select * from ORDERS where CUSTOMER_ID=4;

通过以上5条select语句,Hibernate最后加载了4个Customer对象和5个Order对象,在内存中形成了一幅关联的对象图,参见图2。

n+1查询

Hibernate在检索与Customer关联的Order对象时,使用了默认的立即检索策略。这种检索策略存在两大不足:

(1) select语句的数目太多,需要频繁的访问数据库,会影响检索性能。如果需要查询n个Customer对象,那么必须执行n+1次select查询语句。这就是经典的n+1次select查询问题。 这种检索策略没有利用SQL的连接查询功能,例如以上5条select语句完全可以通过以下1条select语句来完成:

select * from CUSTOMERS left outer join ORDERS 
on CUSTOMERS.ID=ORDERS.CUSTOMER_ID 

以上select语句使用了SQL的左外连接查询功能,能够在一条select语句中查询出CUSTOMERS表的所有记录,以及匹配的ORDERS表的记录。

(2)在应用逻辑只需要访问Customer对象,而不需要访问Order对象的场合,加载Order对象完全是多余的操作,这些多余的Order对象白白浪费了许多内存空间。
为了解决以上问题,Hibernate提供了其他两种检索策略:延迟检索策略和迫切左外连接检索策略。延迟检索策略能避免多余加载应用程序不需要访问的关联对象,迫切左外连接检索策略则充分利用了SQL的外连接查询功能,能够减少select语句的数目。

 

 

附一篇 hibernate的解决n+1的方法

 

    Hibernate的检索策略包括类级别检索策略和关联级别检索策略。 

    类级别检索策略有立即检索和延迟检索,默认的检索策略是立即检索。在Hibernate映射文件中,通过在<class>上配置 lazy属性来确定检索策略。对于Session的检索方式,类级别检索策略仅适用于load方法;也就说,对于get、qurey检索,持久化对象都会被立即加载而不管lazy是false还是true.一般来说,我们检索对象就是要访问它,因此立即检索是通常的选择。由于load方法在检索不到对象时会抛出异常(立即检索的情况下),因此我个人并不建议使用load检索;而由于<class>中的lazy属性还影响到多对一及一对一的检索策略,因此使用load方法就更没必要了。

   关联级别检索策略有立即检索、延迟检索和迫切左外连接检索。对于关联级别检索,又可分为一对多和多对多、多对一和一对一两种情况讨论。

   1)立即检索:这是一对多默认的检索策略,此时lazy=false,outer-join=false.尽管这是默认的检索策略,但如果关联的集合是无用的,那么就不要使用这种检索方式。

  2)延迟检索:此时lazy=true,outer-join=false(outer-join=true是无意义的),这是优先考虑的检索方式。

  3)迫切左外连接检索:此时 lazy=false,outer-join=true,这种检索策略只适用于依靠id检索方式(load、get),而不适用于query的集合检索(它会采用立即检索策略)。相比于立即检索,这种检索策略减少了一条sql语句,但在Hibernate中,只能有一个<set>配置成 outer-join=true.

 

多对一和一对一检索策略一般使用<many-to-one>、<one-to-one>配置。<many- to-one>中需要配置的属性是 outer-join,同时还需要配置one端关联的<class>的lazy属性(配置的可不是<many-to-one>中的lazy哦),它们的组合后的检索策略如下:

 

1) outer-join=auto:这是默认值,如果lazy=true为延迟检索,如果lazy=false为迫切左外连接检索

 

2) outer-join=true,无关于lazy,都为迫切左外连接检索。

 

3) outer-join=false,如果lazy=true为延迟检索,否则为立即检索。

 

   可以看到,在默认的情况下(outer-join=auto,lazy=false),对关联的one端对象Hibernate采用的迫切左外连接检索。依我看,很多情况下,我们并不需要加载one端关联的对象(很可能我们需要的仅仅是关联对象的id);另外,如果关联对象也采用了迫切左外连接检索,就会出现select语句中有多个外连接表,如果个数多的话会影响检索性能,这也是为什么Hibernate通过 hibernate.max_fetch_depth属性来控制外连接的深度。对于迫切左外连接检索,query的集合检索并不适用,它会采用立即检索策略。

 

对于检索策略,需要根据实际情况进行选择。对于立即检索和延迟检索,它们的优点在于select语句简单(每张表一条语句)、查询速度快,缺点在于关联表时需要多条select语句,增加了访问数据库的频率。因此在选择即检索和延迟检索时,可以考虑使用批量检索策略来减少select语句的数量(配置batch-size属性)。对于切左外连接检索,优点在于select较少,但缺点是select语句的复杂度提高,多表之间的关联会是很耗时的操作。另外,配置文件是死的,但程序是活的,可以根据需要在程序里显示的指定检索策略(可能经常需要在程序中显示指定迫切左外连接检索)。为了清楚检索策略的配置效果如何,可以配置show_sql属性查看程序运行时Hibernate执行的sql语句。




转载地址:http://blog.csdn.net/xtayhicbladwin/article/details/4739852



http://www.niftyadmin.cn/n/3648264.html

相关文章

django连接数据库_如何创建Django应用并将其连接到数据库

django连接数据库介绍 (Introduction) A free and open-source web framework written in Python, Django allows for scalability, re-usability, and rapid development. Django是一个用Python编写的免费开放源代码Web框架&#xff0c;可实现可伸缩性&#xff0c;可重用性和…

Jookster脱胎换骨的PeopleSearch

2006年11月18日&#xff0c;Jookster 的这次新变动用户体验相当完美&#xff0c;他们的口号是"Find and Share videos, photos and people from YouTube, Myspace and more!"&#xff01;这次变动真够大的。以前的Jookster是一个通过用户驱动来调整搜索结果的服务。当…

百度的“搜索背后的人”的战略

百度、奇虎、雅虎、Google中国这4家中原逐鹿&#xff0c;百度是战略最稳定也最坚定的公司&#xff0c;产品最稳定也整合得最好的。 譬如说&#xff0c;通过搜人测试版&#xff0c;可以把用户在百度旗下的所有信息整合到一起&#xff1a;百度空间-搜人 测试版这样&#xff0c;当…

如何在Visual Studio Code中使用Git集成

介绍 (Introduction) Visual Studio Code (VS Code) has become one of the most popular editors out there for web development. It has gained such popularity thanks to its many built-in features such as source control integration, namely with Git. Harnessing th…

整合和被收购

分久必合合久必分。按照蚂蚁社区的目前做法看&#xff0c;主题一定不能过于模糊&#xff0e;但是也不能过于细&#xff0e;既不能按照像豆瓣按一本书、一张光碟、一个地方等来组织&#xff0e;也不能像论坛一样按照板块来组织。按照百度帖吧或者博啦360的形式是可以的。要能够机…

在Eclipse中运行Web项目时显示404错误

为了一个404错误整整花了一个下午&#xff0c;网上的各种方法都尝试了然后还是没有用 最早可以运行&#xff0c;又不想重新搭建换环境就就从头改 错误解决方法: 检查server中的web.xml文件 <param-value>的默认值是false&#xff0c;将false改为true,重新运行即可 在WebC…

[Python]Python/PHP如何查询sql server中NTEXT类型数据

[Python]Python/PHP如何查询sql server中NTEXT类型数据VersionDateCreatorDescription1.0.0.12006-11-23郑昀草稿继续阅读之前&#xff0c;我们假设您熟悉以下知识&#xff1a;n Python / PHPn SQL Server 2000 SP4以上版本的Microsoft sql servern py…

django启用超级管理员_如何启用和连接Django管理界面

django启用超级管理员介绍 (Introduction) If you have followed along in the Django Development series, you’ve started a Django application, connected your application to MySQL, and created the database models for the Posts and Comments data within your blog…