`

iBATIS使用之高级查询技术详解

    博客分类:
  • OPEN
阅读更多


ibatis in action为ibatis展现自己强大功能提供了保证,ibatis也可以完成更为复杂的任务。在本章中,我们会了解新的技术,减少我们的编码量;以及改善性能、降低资源消耗(footprint)的几种方法。
1 使用ibatis操作xml
译者注:ibatis的java版本可以操作基于xml的数据。但意义并不是很大,在以后的版本中该特性可能会被移除。ibatis.net则未提供该功能。
2 使用映射语句关联对象
ibatis框架也提供了多种方法用以关联复杂的对象,比如订单(order)和它的订单项(order item)(还有它们的相关产品、顾客等等)。每种方法都有其优点和缺点,正所谓“尺有所短,寸有所长”,每一种方案都不是完美的。应根据需要来选择适合的方案。
注意:为简短起见,在本章的余下的例子中,我们将省略那些对于演示来说不必要的数据。例如,当我们获取了一个顾客(customer)对象,我们不会获取它的所有字段,而是仅仅获取它的主键和外键。
2.1 复杂的集合属性
在第4章中,我们学习了如何使用select语句从数据库获取数据。在那些例子中,我们获取的结果仅仅是单个对象,即使是连接多表也是如此。事实上,如果您有多个复杂对象,也可以使用ibatis加载它们。
如果我们的应用程序模型与数据模型比较类似,那么这个功能会很有用。可以考虑根据对象的关系(关联)来定义数据模型,然后使用ibatis将它们一起加载。例如,如果在数据库中,account记录对应着相关的order记录,而order又对应着相关的orderitem记录,可以为这些记录建立关系,当我们请求一条account记录时,可以一并获取所有的order和orderitem记录。下面的代码清单显示了如何定义我们的sql映射:

图1sql映射
先来看看结果映射(result map,即上面的resultaccountinfomap,resultorderinfomap和resultorderitemmap),前两个map都用到了select特性。这个特性告诉ibatis,属性的值将由另一个映射语句来设置,语句的名称就是select特性的值。例如,我们执行getaccountinfolist语句时,resultaccountinfomap结果映射有一个子元素:

图2select特性的值
它的作用是告诉ibatis,account对象的orderlist属性的值由chgetorderinfolist语句来设置,同时把accountid列的值传给chgetorderinfolist作为参数。类似地,在设置order对象的orderitemlist对象时,也会执行getorderitemlist语句。
这个功能给我们带来便利的同时,也带来了两个问题。首先,创建包含大量对象的列表可能会消耗大量的内存。其次,这种方法会导致数据库的i/o问题,其原因是所谓的“n+1 select”现象,这个现象将在后面讨论。对于每个问题,ibatis框架都提供了解决方案,但是注意,没有哪一种能同时解决这两个问题。
数据库i/o
数据库i/o是数据库使用状况的一项指标,也是数据库性能的主要瓶颈之一。在读取或写入数据库时,数据必须要经历从磁盘到内存或者从内存到磁盘的转换,这个过程是比较耗时的。在程序中使用缓存可以减少对数据库的访问,但这种方法使用时要谨慎,否则也会引发问题。要了解ibatis中的缓存机制,可以参看第10章的内容。
在使用关联数据时,可能会遭遇数据库i/o问题。考虑一下这个场景:有1000个account,每一个关联了1000个order,而每个order则包含25个orderitem。如果尝试将所有这些数据加载到内存,执行的sql语句要超过1000000行(1条用来查询account,1000条用于order,1000000条用于orderitem),而创建的对象大约为2500万——如果你真敢这么做,等你的系统管理员收拾你吧。
分析n+1查询问题
n+1查询问题是由于试图加载多个父记录(比如account)的子记录(order)而引起的。因此,在查询父记录时,只需要1条语句,假设返回n条记录,那么就需要再执行n条语句来查询子记录,引发所谓的“n+1查询”。
这些问题的解决方案
延迟加载(lazy load,在2.2中详细讲述)可以解决一部分内存问题,它将加载过程打散为一些更小的过程。但是,它并没有解决数据库i/o问题,在最坏的情况下,它对数据库的访问次数与非延迟加载的版本是一样的,因为加载数据时它的方法还是n+1查询(这个我们将在2.3中解决)。另一方面,当我们解决了n+1查询问题,减少了对数据库的访问,但我们的查询结果却包含着2500万行记录!
要决定是否使用复杂属性,我们需要理解数据库以及应用程序对数据库的使用方式。如果您使用了本节中的技术,那可以省不少事儿,但如果误用了它,也会有大麻烦。在接下来的两节中,我们会分析如何根据目标选择合适的策略。
让我们从这个问题开始:像上面例子那样将account关联到order并将order关联到orderitem是否合适?实际上,不是——order-to-orderitem关系是固定的,但是account-to-order关系则是不必要的。
我们是如是推理的:没有所属的order,orderitem是没有意义的,而account则是有意义的。一般情况下,没有orderitem,order没什么大用,相对的,不属于任何order的orderitem是没有意义的。另一方面,一个account则可以认为是一个完整的对象。
但在我们的例子中,这种关系可以良好地描述相关的技术,因此我们会在一段时间内一直使用它。
2.2 延迟加载(lazy loading)
首先来看看延迟加载。如果不是对所有数据都马上用到,那么延迟加载是有用的。例如,我们的程序首先在一个网页显示所有account,然后销售代理(我们的客户)可以点击一个account来查看该account的order列表,然后可以再点击一个order来查看其所有的orderitem信息。在这种情况下,每次都仅查询一个列表。这是对延迟加载的合理使用。
译注:在ibatis的java版本中,使用延迟加载前还需要进行配置sqlmapconfig.xml以打开该功能。在.net版本中不需要配置等价的sqlmap.config。
使用了延迟加载后,我们就可以更合理地进行对象创建和对数据库的访问。(还是使用上面的例子)如果一个用户关注到orderitem层次的数据,我们需要进行三次查询(一次是为account,一次是order,还有一次是orderitem),应用程序则要创建2025个对象(1000个account, 1000个order,25个orderitem)。效果明显!而我们要做的仅仅是修改xml配置文件的一个特性(attribute)而已,无需改动代码。
在一项不太严谨的测试中,我们发现,对于同样的对象关联关系(如上面的account- order- orderitem),在加载第一个列表数据时(account列表),没有使用延迟加载的版本花费的时间是使用了延迟加载的版本的三倍。但是,在加载所有数据时,延迟加载的版本的时间却多了20%。很明显,我们要根据数据加载的数量和时机来确定是否采用延迟加载。此时,经验是最重要的。
而有时您并不希望推迟数据的加载,而是希望在第一次请求的时候加载所有的数据。在这种情况下,您可以使用下节中的技术,它仅需要一次查询即可。下节的方法避免了“n+1查询”。
2.3 避免“n+1查询”问题
我们来考虑如何避免“n+1查询”问题,这里可以使用连接语句(join)。
这里用到的技术同前面类似。简单的说,使用result map来定义对象间的关系,将顶层的result map关联到映射语句。下面的例子的data map文件结构与前面大体一致,但是只需要执行一条sql语句。
这里面有三个result map,一是关于account的,二是关于order的,三是orderitem的。
关于account的result map有两个作用:
映射account对象本身的属性。
告诉ibatis如何映射下一层的关联对象,这里是orderlist。
order的result map作用与之类似。
映射order对象本身的属性。
告诉ibatis如何映射下一层的关联对象,这里是orderitemlist。

图3orderitemlist
我们的不太科学的测试表明,在加载少量数据时,该方法将原先方法的性能提高为7:1。我们猜想,对于例子中使用的2500万条数据,两种方法仍然不错。
译注:在ibatis.net datamapper 1.1中,添加了groupby特性,它将进一步改善性能。详细内容请参看相关文档,本文使用的是datamapper 1.5.1。
需要注意的是,尽管性能得到改善,内存的消耗仍然与没有使用延迟加载的版本相同。所有的记录一起放入内存,因此尽管它稍微快了一点,但内存的消耗仍是问题。
译注:在加载复杂属性时可能出现两方面的问题,一是对数据库的访问,二是创建对象时对内存的消耗。我们可以采用延迟加载或join的方法来解决这些问题,但是两者都不是万灵药。延迟加载的原理时推迟对复杂属性的加载,以减少对数据库的访问和对象的创建,但它的前提是复杂属性不会马上用到,否则的话,延迟就失去意义。join的原理是通过一条sql语句加载所有数据,这样可以大幅度减少对数据库的访问量,它的前提是对象的数量不会太多。该如何选择呢?下面的表格给出了简单的原则:

图4简单的原则
译注:另外,我觉得还有一条很重要的原则,那就是永远只加载必需的数据。以上面的例子来说,我们不太可能会同时显示1000个account给用户看,这时就不要同时加载1000个account的数据了,可以通过分页只显示50条数据,在此基础上再应用延迟加载或join效果会很不错。
分享到:
评论

相关推荐

    mysql,jdbc详解,与ibatis对比。批量查询,分页处理。

    尝试自己编写一些简单的JDBC示例,并逐步过渡到使用iBatis或其他高级框架。 通过对MySQL的基本操作、JDBC的工作原理以及iBatis与JDBC的对比分析,我们可以更全面地理解数据库编程的关键概念和技术要点。希望本文...

    ibatis 一个简单的项目详解

    ibatis是一个支持普通SQL查询、存储过程以及高级映射的优秀数据库持久层框架。它可以将接口和Java的POJOs(Plain Old Java Objects)映射成数据库中的记录。 #### 二、项目环境配置 项目基于以下技术栈搭建: - **...

    ibatis高级特性

    ### ibatis高级特性详解 #### 一、引言 Ibatis 是一款优秀的持久层框架,它简化了 Java 开发者与数据库之间的交互过程。本文将详细介绍 ibatis 的一些高级特性,包括数据关联、延迟加载、动态映射以及事务管理等...

    ibatis技术总结

    ### ibatis技术总结 #### 1. 创建iBatis工程的步骤 在开始构建一个基于iBatis的应用之前,需要遵循一系列明确的步骤来确保项目的顺利进行: 1. **建立数据库**:首先需要设计并创建数据库,这一步骤至关重要,...

    Java数据库技术详解 DOC简版

    第一篇 数据库基础篇 第1章 Java和数据库 1.1 Java概述 1.2 Java的开发和运行环境 ...第17章 JSP、Servlet和iBatis结合使用 第五篇 XML篇 第18章 XML存储数据 第六篇 项目实战篇 第19章 学籍管理系统

    iBatis入门教程

    ### iBatis入门教程知识点详解 #### 一、iBatis简介 iBatis是一个开源框架,用于简化Java应用程序与数据库之间的交互。它基于SQL语句执行查询,并将结果映射到Java对象上,从而降低了Java层代码与SQL语句之间的...

    spring mvc + ibatis + Oracle + ajax 轻量级架构搭建及详解

    在本项目中,我们探讨的是如何使用Spring MVC、iBatis、Oracle数据库以及Ajax技术构建一个轻量级的Web应用程序架构。Spring MVC是Spring框架的一部分,主要负责处理HTTP请求和控制应用程序的流程;iBatis则是一个SQL...

    idea-mini-ibatis.zip

    **Idea-mini-ibatis 插件详解** `idea-mini-ibatis` 是一款专为 IntelliJ IDEA 设计的轻量级 iBatis/MyBatis 开发插件,旨在简化和优化在 IDE 中进行 iBatis 或 MyBatis 框架的开发工作。这个插件是开源的,意味着...

    ibatis3.0中in的用法

    ibatis3.0(也称为MyBatis)是一个支持普通SQL查询、存储过程以及高级映射的优秀持久层框架。它消除了几乎所有的JDBC代码和参数的手工设置以及结果集的检索;它可以使用简单的XML或注解进行配置和原始映射,将接口和...

    ibatis 开发指南

    ### ibatis 开发指南知识点详解 #### 一、ibatis简介 ...通过对ibatis的基本概念、快速入门和高级特性的详细介绍,我们不仅可以了解如何有效地使用ibatis,还能深入理解其背后的设计理念和技术优势。

    ibatis资料

    **Ibatis动态查询详解** Ibatis,全称MyBatis,是一个优秀的持久层框架,它支持定制化SQL、存储过程以及高级映射。Ibatis避免了几乎所有的JDBC代码和手动设置参数以及获取结果集。Ibatis可以使用简单的XML或注解...

    iBATIS_2.0_开发指南

    ### iBATIS 2.0 开发指南知识点详解 #### 一、iBATIS简介 iBATIS是一款开源的持久层框架,它提供了一种“半自动化”的对象关系映射(Object-Relational Mapping, ORM)实现方式。与Hibernate、Apache OJB等“一站式...

    manning.ibatis.in.action.jan.2007.rar

    7. 高级话题:如性能优化、安全考虑、iBATIS与其他技术(如Spring)的集成等。 8. 实战项目:通过一个完整的项目案例,展示如何在实际开发中运用iBATIS。 通过阅读《iBATIS in Action》,开发者不仅可以掌握iBATIS...

    ibatis学习资料

    #### 高级查询技术 - **映射继承**:支持继承映射关系,简化重复的映射配置。 - **XML返回类型**:允许查询结果以XML格式返回。 - **RowHandler接口**:通过实现`RowHandler`接口来自定义结果集处理逻辑。 #### ...

    ibatis和mybatis的前世今生.txt

    ### ibatis与mybatis的发展历程及技术要点 #### 一、ibatis的起源与功能特点 ibatis作为一款开源的Java持久层框架,在其诞生之初便致力于解决Java应用程序中的数据库操作问题。它通过将SQL语句封装在XML配置文件中...

    Java ibatis ext spring DWR SQL全套PDF

    Java开发领域涵盖了许多技术栈,本套PDF集合涵盖了Java企业级开发中的重要组件和技术,包括iBatis、EXT、Spring和Direct Web Remoting (DWR)以及SQL。这些技术是构建高效、可扩展的Web应用的基础,对于Java开发者来...

    IBATIS学习笔记

    ### IBATIS学习笔记知识点详解 #### 一、IBATIS简介 iBatis是一个用于Java的数据持久化框架,类似于Hibernate、JDO和EJB等技术。它的主要特点是将对象映射为SQL语句,这使得开发人员可以更加灵活地控制SQL的执行,...

    iBatis入门

    ### iBatis入门详解 #### 一、iBatis简介 iBatis是一个开源的持久层框架,它提供了一种简单而强大的对象关系映射(Object/Relational Mapping,简称ORM)解决方案。与传统的JDBC相比,iBatis在很大程度上简化了...

Global site tag (gtag.js) - Google Analytics