iBATIS就是我们通常所说的数据映射器(data mapper)。Martin Fowler在他的著作Patterns of Enterprise Application Architecture(Addison-Wesley Professional, 2002)中,对数据映射器模式是这样描述的:
所谓映射器,是用于在对象和数据库之间搬运数据,同时保证对象、数据库以及映射器本身都相互独立。
Martin在区分数据映射以及元数据映射上,确实做了一件非常出色的工作,元数据映射正是适合使用对象/关系映射(O/RM)工具的地方。O/RM工具将数据库表及其列映射为应用中的类及字段。或者说,O/RM工具在数据库的元数据与类的元数据之间建立起了一种映射关系。图2-1展示了所谓的O/RM,它在一个类与数据库表之间建立了映射关系。在这种情况下,类的每一个字段都被映射为数据库中相应表的唯一列。
iBATIS与之不同,它不是直接把类映射为数据库表或者说把类的字段映射为数据库列,而是把SQL语句的参数与结果(也即输入和输出)映射为类。正如你在本书的剩余部分中将会学到的,iBATIS在类和数据库表之间建立了一个额外的间接层,这就为如何在类和数据库表之间建立映射关系带来了更大的灵活性,使得在不用改变数据模型或者对象模型的情况下改变它们的映射关系成为可能。其实我们这里讨论的这个间接层就是SQL。SQL这个额外的间接层使得iBATIS能够更好地隔离数据库设计和应用中使用的对象模型。这就使得它们两者之间的相关性能够降至最少。图2-2展示了iBATIS如何使用SQL映射数据。
图2-2 iBATIS的SQL映射
正如你在图2-2中所看到的,iBATIS的映射层其实就是SQL。iBATIS让你自己写SQL语句,iBATIS负责在类的字段和数据库表的列之间映射参数和结果。基于这个原因,也考虑到与其他各种各样的映射方式的区分,为避免混淆,iBATIS小组通常将所谓的“数据映射器”称为SQL映射器(SQL mapper)。
1 映射SQL语句
任何一条SQL语句都可以看作是一个函数,有输入输出集合。输入即参数(parameter),通常可以在SQL语句的WHERE子句中找到。输出则是SELECT子句中指定的那些列。图2-3描述了这个思想。
图2-3 SQL语句可以被看作一个包含输入输出的函数
这种方式的最大优点就在于SQL语句使得开发者能够自己把握巨大的灵活性。他可以在不改变数据模型的前提下轻易地操纵数据以适应对象模型。甚至,开发者还可以通过数据库内建的函数和存储过程引入多表和结果集。总之,他们可以随心所欲地利用SQL的强大能力。
iBATIS使用一个简单的XML描述文件来映射SQL语句的输入和输出。代码清单2-1给出了一个这样的例子。
代码清单2-1 一个SQL映射的例子
从以上代码中我们看到了一条SELECT语句,它返回address表中的数据。从<select>元素的parameterClass属性中我们可以看出该语句使用一个Integer对象作为参数,该参数是通过WHERE子句中的#id#符号标记的;从<select>元素的resultClass属性我们还可以看出该语句的结果是一个Address类的实例,假设Address类的所有字段名与SELECT语句中指定的各个列的别名(通过as关键字)相同。例如,ADR_ID列别名为id,故会映射到Address类中名为id的字段上。不论你是否相信,要映射一个SQL语句使其接受一个Integer作为参数并返回一个Address对象作为结果,你要做的就是这些了。用于执行以上语句的Java代码如下:
Address address = (Address) sqlMap.queryForObject("getAddress",
new Integer(5));
SQL映射这个概念具有很好的可移植性,可应用于任何一个功能完备的编程语言。例如,基于iBATIS.NET的C#代码就与之前的Java代码几乎是一模一样的:
Address address = (Address) sqlMap.QueryForObject("getAddress", 5);
当然,iBATIS针对SQL映射还有许多高级选项,特别是针对映射的返回结果。关于这些高级选项,我们会在本书的第二部分“iBATIS基础”中详细讨论。现在,我们最重要的任务就是了解iBATIS的特性和好处,以及它如何工作。
2 iBATIS如何工作
尤其要注意的是,有了iBATIS,你就再不需要直接编写JDBC代码或ADO.NET代码了。JDBC和ADO.NET的确非常强大,但使用起来总不免觉得太过繁琐。代码清单2-2给出了一个使用JDBC的例子。
代码清单2-2 使用JDBC的代码示例
从这个例子中很容易看出,使用JDBC API编写代码需要许多额外的工作。尽管如此,每一行代码又都是必不可少的,所以要减少代码量还真不是一件容易的事情。最多也只不过能将其中的一些代码挪到某个实用方法(utility method)中,最明显的就是那些关闭资源(如PreparedStatement和ResultSet)的代码。
其实,如果使用iBATIS,iBATIS在后台也是运行这些相同的JDBC代码。iBATIS会获取数据库连接,设置SQL语句的参数,执行SQL语句,获取执行结果,并在最后关闭所有的资源。然而,你需要自己亲自编写的代码量却大大地减少了。代码清单2-3给出了使用iBATIS运行相同的SQL语句时你需要编写的代码。
代码清单2-3 iBATIS显然比JDBC要精简得多
根本无须比较,iBATIS代码明显更加简洁,更容易阅读,因此也更容易维护。本章稍后会讨论更多关于使用iBATIS的好处。但是现在,你最关心的可能是如何用Java代码运行以上的“SQL语句”。其实就像你在之前的示例中已经看到的,运行它仅仅需要一行简单代码:
Employee emp = (Employee) sqlMap.queryForObject("getEmployee",
new Integer(5));
没什么好多说的。这行代码会执行相应的SQL语句,设置其参数并返回一个真实的Java对象作为结果。SQL语句被“干干净净”地封装在Java代码之外的一个XML文件中。iBATIS负责管理幕后的所有资源,其运行的实际效果与我们之前所见的代码清单2-2所示的JDBC的例子是完全一样的。
这就引起一个问题,iBATIS对所有的系统来说都以一样的方式工作吗?或者它仅仅是适用于某一类特定的应用?以下几节我们将回答这个问题,首先从iBATIS是多么的适合于小型应用说起。
2.1. iBATIS之于小型、简单系统
小型应用通常只涉及一个数据库,只有一些相当简单的用户接口和领域模型。它的业务逻辑层非常简单,有时对一些简单的只涉及增查改删(CRUD:Create, Read, Update, Delete)操作的应用来说甚至根本就不存在业务逻辑。iBATIS之所以非常适合于小型应用,有3个原因。
第一,iBATIS自己就很小并且简单。它不需要服务器或者其他任何类型的中间件。不需要任何额外的基础设施(infrastructure)。iBATIS也没有任何第三方依赖。iBATIS的最简安装只需要2个JAR文件,总计不过375KB。除了需要配置一下你的SQL映射文件外,iBATIS不需要进行任何安装,因此只需要几分钟时间你就可以拥有一个可工作的持久层了。
第二,iBATIS不会对现存应用的设计或者数据库结构强加任何影响。因此,如果你有一个小型系统,且已经部分实现或者甚至已经发布了,则你仍然可以重构你的持久层以使用iBATIS,这非常简单。因为iBATIS很简单,所以它根本不会使得应用的架构过分复杂。而如果使用对象/关系映射工具或者代码生成工具,因为它们都事先就对应用以及数据库的设计做了某些假设,因此它们不可能对应用的架构毫无影响。
最后,只要你有过软件开发的经验,相信你就不会怀疑,任何一个小软件都几乎不可避免地有一天会成长为一个大软件。所有成功的软件都有进一步成长的趋势。这是一件好事,而我们接下来想说的就是,iBATIS同样非常适合于大型系统,它甚至可以扩展以满足企业级应用的需要。
2.2 iBATIS之于大型、企业级系统
iBATIS就是为企业级应用而设计的。最重要的是,iBATIS在这个领域比之其他解决方案有着大量的优点。iBATIS最初的创建者只有从大型应用到企业级应用系统的开发经验。这一类系统通常都涉及不止一个数据库,且所有这些数据库都是不可控的。在第一章中我们讨论了各种类型的数据库,包括企业级数据库、私有数据库和遗留数据库。作者创建iBATIS框架一个很重要的原因就是针对这样的数据库。因此,iBATIS拥有许多使其非常适合于企业应用环境的特点。
其实iBATIS适用于大型系统中的第一个原因我们已经说过了,不过这个原因的确很重要,所以我们还是想再强调一下:iBATIS没有对你的数据库模型和对象模型的设计做任何假设。不论你的应用中这两个模型之间是多么不匹配,iBATIS都能适用。更进一步,iBATIS没有对你的企业级应用的架构做出任何假设。不论你对数据库是根据业务功能纵向划分,还是按照技术横向划分,iBATIS都允许你高效地处理数据并将它们整合到你的面向对象的应用中去。
第二点,iBATIS的某些特性使得它能够非常高效地处理大型数据集。iBATIS支持的行处理器(row handler)使得它能够批处理超大型记录集,一次一条记录。iBATIS也支持只获取某个范围内的结果,这就使得你可以只获取那些你当前亟需的数据。例如,假设你获取了10,000条记录,而你其实只需要其中的第500至600条,那你就可以简单的仅获取这些记录。iBATIS支持驱动提示使得执行这样的操作非常高效。
最后一点,iBATIS允许你用多种方式建立从对象到数据库的映射关系。一个企业级系统只以一种模式工作的情况是非常少见的。许多企业级系统需要在白天执行事务性的工作,而在晚上执行批处理工作。iBATIS允许你将同一个类以多种方式映射,以保证每一种工作都能以最高效的方式执行。iBATIS同样支持多种数据获取策略。例如,你可以选择对某些数据进行懒加载,也可以将一个复杂的对象图只用一条联合查询SQL语句就同时加载完毕,从而避免严重的性能问题。
以上所说的这些似乎好像在自我推销了。那么,既然我们已经进入了这种状态,为何不继续深入研究一下你需要使用iBATIS的理由呢?我们会在2.3节做这件事情。并且为了公平起见,在2.4节中,我们还会讨论一些你不应该使用iBATIS的情况。
3 为何使用iBATIS
我们有充足的理由说明,你几乎可以在任何系统中使用iBATIS。正如你在本章之前的内容中所学到的,像iBATIS这样一个框架能够使你的应用从架构级别上开始受益。本节中我们就将讨论这些益处以及使这些益处成为可能的iBATIS特性。
3.1 简单性
iBATIS被广泛认为是当今可用的最简单的持久化框架之一。简单性的理念根植于iBATIS开发团队,它在iBATIS的所有开发目标中居于首位。这种简单性的取得是因为iBATIS直接构建于JDBC和SQL之上。iBATIS对于Java开发者来说非常简单,因为它除了不用编写那么多代码外与JDBC的工作机制非常相像。几乎你知道的关于JDBC的一切都对iBATIS同样适用。你几乎可以这样认为,iBATIS就是以XML的形式来描述的JDBC代码。有人说,iBATIS拥有许多JDBC所没有的架构级的优点,这些优点我们随后就将讨论。iBATIS对于数据库管理员以及SQL程序员来说也非常容易理解。iBATIS配置文件几乎人人都能读懂,只要他有SQL编程的经验。
3.2 生产效率
任何一个优秀的框架,其目的都是使得框架的使用者能够获得更高的生产效率。一般情况下,框架负责处理公共的任务,减少编写那些像样板一样的重复代码,以及解决复杂的架构级的问题。iBATIS在给开发人员带来更高的开发效率方面做得非常成功。在意大利的Java用户组(Java Users Group)所做的一个案例调查中(参见www.jugsardegna.org/vqwiki/jsp/Wiki?IBatisCaseStudy),Fabrizio Gianneschi发现iBATIS减少了持久层大约62%的代码量。所以能减少如此之多的代码量,究其原因是开发者再不需要编写繁琐的JDBC代码了。SQL语句仍然是硬编码的,不过就像你在本章之前所看到的,SQL不是问题——问题在于JDBC API,对于ADO.NET而言也是如此。
3.3 性能
性能这个话题无疑会引起框架开发者、框架使用者以及商业软件开发商之间的一场激烈争论。事实是,从一个较低的级别来看这个问题,无疑所有的框架都会带来一定的性能损失。一般来说,如果你比较硬编码的JDBC代码和iBATIS代码,做一个1,000,000次的for循环,你会发现JDBC在性能上的确有一些优势。幸运的是,在现代应用开发中,以上这样的for循环带来的性能损失并不重要。真正重要的是,你如何从数据库中获取数据,何时获取,获取的频率又是多少。例如,分页查询之所以能大大提高应用的性能就在于,它不会将可能成千上万条的记录从数据库中一次取出。同样地,使用像懒加载这样的特性可以避免加载那些在当前情况下并不需要的数据。另一方面,如果你确定需要加载一份复杂的对象图,涉及到来自多个表的大量数据,如果能仅用一条SQL语句就完成所有对象的加载显然可以大大提高效率,iBATIS支持使用这样的SQL语句。iBATIS支持许多性能优化措施,我们将在本章之后的章节中详细讨论。就目前而言,最重要的是要知道iBATIS总是能通过一种简单的方式来配置和使用,其性能与JDBC相当,甚至更好。另一个需要重点考虑的问题就是,并不是所有的JDBC代码都是编写良好的。JDBC API非常复杂,编写正确的代码需要非常小心。不幸的是,大量的JDBC代码都编写得相当糟糕,因此从较低层次上看甚至还没有iBATIS工作得好。
3.4 关注点分离
在典型的JDBC代码中,在应用的各个层中都能找到与数据库相关(例如获取连接、遍历结果集)的代码,这并不稀奇。相信大家都见过甚至开发过这样糟糕的应用——所有的逻辑都在一个JSP页面中完成,连接数据库、执行SQL语句,遍历结果集,当然还有散落其间的HTML代码。这样的代码简直是一个噩梦。在第一章中我们已经讨论了对应用分层的重要性。我们已经看到了如何从一个较高的角度对应用分层,以及持久层内部又是如何进一步分层的。iBATIS通过帮助管理所有这些持久化相关的资源来支持分层,这些资源包括数据库连接(database connection)、prepared statement以及结果集(result set)。iBATIS提供了一组数据库无关的接口以及API,使得应用的其它部分能够通过使用这组接口和API保持与数据库相关资源的独立性。使用iBATIS,你的代码总是在直接与严格的对象打交道,再也不用管那些随意的结果集了。iBATIS实际上使得你难以违背对应用分层这样的最佳实践。
3.5 明确分工
一些数据库管理员是如此热爱他们的数据库,以至于不愿意让任何其他人来为数据库编写SQL。而有一些人又是如此擅长编写SQL,以至于其他人都想让他们来做这项工作。无论是什么原因,在你的开发团队中实现人尽其才总是有利的。如果你的团队中有人尤其擅长于编写SQL,但是对于Java或C#却不那么在行,那么就可以让他们专门编写SQL。iBATIS使得这种分工成为可能。因为在iBATIS中,SQL语句在很大程度上同应用的源代码是分离的,SQL程序员可以按照SQL原本的方式来编写它,而不必担心有关SQL字符串连接的问题。即使由相同的开发者来编写Java代码和SQL,在数据库性能调整(performance tune)的过程中也会有一个来自DBA的常见请求,即“显示出SQL”。用JDBC来完成此事并不容易,因为SQL隐藏得很深,是连接一堆分散的字符串得到的,甚至还可能是在递归语句和条件语句中动态地创建的。如果使用对象关系映射,情况就更加复杂了,因为你通常必须运行应用然后才能log出这些SQL语句,即使你找到了它们,你也根本不能改变它们。iBATIS则提供了充分的自由,使得任何人都可以开发、观察并且修改在数据库中执行的SQL语句。
3.6 可移植性:Java、.NET或者其他
iBATIS是可移植的。由于它相对简单的设计,它几乎可以用任何一种语言在任何一个平台上实现。书写本书时,iBATIS支持3种最受欢迎的开发平台:Java、Ruby和微软.NET的C#。
当前,配置文件并不完全跨平台兼容,但是我们正在计划使它们更加兼容。重要的是,概念和方法都是可移植的。这就使你能够保证你所有的应用在设计上是一致的。和其他框架相比,iBATIS可以处理更多语言以及更多类型的应用,而无需考虑应用设计的不同。如果应用的一致性对于你来说很重要的话,使用iBATIS就可以很好地帮你达到一致性。
3.7 开源和诚实
开始时我们说本节有“自吹自擂”之嫌。事实上,iBATIS是免费的开源软件。无论你是否使用它,我们都不会因此而获得哪怕是一分钱的利益。你已经买了本书,所以我们已经获得了我们该得的利益。开源软件的最大的优点之一就是诚实。我们没有任何理由对你撒谎。因此下面我们将要做的事在商业软件文档中就是非常罕见的:我们将要讨论一些你可能不应该使用iBATIS的情况,并且提出一些合适的替代方案。
4 何时不该使用iBATIS
每个框架都是建立在一定的规则和约束之上的。底层的框架,如JDBC,提供了一个灵活且完备的功能集合,但是它们使用起来却更难也更繁琐。高层的框架,如对象/关系映射工具,使用就更加方便并且可以帮你节省大量工作,但是它们是建立在更多的假设和约束的基础上的,这使得它们只能适用于较少的应用。
iBATIS是一个中层的框架。它比JDBC更高层一些,但是相对于对象/关系映射工具,又要更底层一些。这使得iBATIS处于一个很独特的位置上,使它能够适用于一些较为特别的应用。在本书前面的部分,我们讨论了为什么iBATIS对于多种应用类型都是有用的,包括小的桌面应用,和较大的、企业级的Web应用——以及任何介于这两者之间的应用类型。那么,iBATIS不适用的场合是什么呢?下面几节就将详细描述不适合使用iBATIS的各种情况,并且给出有关替代方案的建议。
4.1 当你能永远拥有完全控制权时
如果你能够保证拥有对应用设计和数据库设计的完全控制权,那你一定是一个非常幸运的人。这在商业环境或者任何一个核心工作不是软件开发的行业中都是非常少见的。然而,如果你在一个软件公司工作,并且在开发一个你拥有完全设计控制权的且由你发售的产品时,那么你可能恰好处于这种情况。
当你具有完全控制权时,就有充分理由使用一个完全的对象/关系映射方案,如Hibernate。你可以充分利用对象/关系映射工具所能提供的设计优势并提高生产率。可能根本没有来自企业数据库组的干扰,也不需要与遗留系统整合。此外,数据库可能是与应用一同部署的,这使得它属于应用数据库的范畴(参见第1章)。使用Hibernate的应用的一个很好的例子就是,Atlassian的JIRA。它们提供了一个问题跟踪软件,作为一个他们可以完全控制的发布产品。
然而,还需要考虑应用未来的发展。如果数据库有可能超出应用开发者的控制,那么你就必须仔细考虑一下使用对象/关系映射将对你的持续化策略带来怎样的影响。
4.2 当你的应用需要完全动态的SQL时
如果你的应用的核心功能是动态生成SQL,那么iBATIS就是错误的选择。iBATIS支持非常强大的动态SQL特性,这些特性又反过来支持高级查询能力,甚至一些动态更新功能。然而,如果你的系统中每个语句都是动态地生成的,那么你最好使用原始的JDBC,甚至可以创建你自己的框架。
iBATIS的强大功能之一就是它允许你拥有完全的自由,可以手工编写和直接操作SQL。当应用中大部分的SQL都是从某些SQL生成类动态地生成时,这种优势就会很快丧失。
4.3 当你并没有使用关系数据库时
对于关系数据库之外的其他数据库,也存在可用的JDBC驱动。对于平板文件,微软Excel电子数据表,XML,以及其他类型的数据存储平台,都有相应的JDBC驱动。虽然一些人在iBATIS中使用这些驱动也获得了成功,但是对于大多数用户我们并不推荐使用这些驱动。
iBATIS并不会对你的环境做出任何假设。但是它确实期望你使用的是真正的关系数据库,即支持事务、相对典型的SQL、和存储过程这些语义的关系数据库。即使一些非常著名的数据库也可能不支持关系数据库的某些重要特性。如MySQL的早期版本就不支持事务,因此iBATIS不能很好地处理MySQL。幸运的是,当前的MySQL已支持事务并且还有一个非常符合规范的JDBC驱动。
如果你使用的不是真正的关系数据库,我们推荐你最好使用原始的JDBC,甚至更底层的文件I/O API。
4.4 当iBATIS不起作用时
随着社区提出的需求越来越多,iBATIS也不断地实现了许多非常好的特性。然而,iBATIS是有其自己的发展方向和设计目标的,这样一来它有时候就有可能会同一些应用的需求发生冲突。人们在软件帮助下可以完成很多神奇的事情,但是有时候由于需求过于复杂,软件可能会完全不起作用,iBATIS也是如此。虽然我们也可以在iBATIS中添加特性以支持这些复杂的需求,但是这么做可能会极大地提高复杂性,甚至可能会改变iBATIS框架的适用范围。因此,我们不会修改框架。为了解决以上问题,我们将提供可扩展的接口,这样你就可以扩展iBATIS以满足几乎任何需求。事实上,有时候iBATIS就是不起作用。此时,最好另寻一个更好的解决方案,而不是“霸王硬上弓”地将iBATIS(或者其他任何框架)用在不合适的地方。
下面我们不再讨论使用iBATIS的是是非非了,还是来看一个简单的例子吧。
5 5分钟内用iBATIS创建应用
iBATIS框架实际上非常简单,要开始使用它也同样非常简单。那么究竟有多简单呢?事实上,它是如此简单,以至于你可以用iBATIS在5分钟之内创建一个完整的应用——不是一个大型的企业资源规划(Enterprise Resource Planning,ERP)方案或者一个大型电子商务网站,而是一个简单的命令行工具,用于执行一个SQL映射文件中的一条SQL语句并且向控制台输出执行结果。下面将要给出的例子将配置一条简单的静态SQL语句,用于查询一个简单的数据库表格,并且把它以如下形式输出到控制台:
这种数据输出方式并不是最漂亮的,但是由此你可以了解该应用到底要做些什么。在下面几节中,我们将逐步从无到有地实现此功能。
5.1 安装数据库
为了满足示例应用的目的,我们将使用MySQL数据库。iBATIS框架可以使用任何数据库,只要该数据库具有符合规范的JDBC驱动。你只需要在配置文件中提供驱动的全限定类名以及一个JDBC URL即可。
安装数据库服务器超出了本书所讨论的范围,因此我们假设数据库服务器已经安装好并且可用了,然后告诉你在此基础之上需要做些什么。以下的MySQL脚本用于构造了我们将要使用的表格,并且在其中添加了一些示例数据:
如果你已经安装了一个不同的数据库服务器,其中包含一些其他数据,并且你想要在这些数据上执行某些SQL查询,你可以大胆地在本例子中使用它。你只需要修改SqlMap.xml文件中的查询语句,以包含你的SQL,同时还需要修改SqlMapConfig.xml文件以配置iBATIS使用你的数据库。为使整个例子成功运行,你还需要知道驱动的名称、JDBC URL、以及连接时的用户名和密码。
5.2 编写代码
由于本例是我们给出的第一个完整的例子,同时也只是对使用iBATIS的一个介绍,因此它的代码将会比真正的应用要简单得多。类型安全和异常处理我们以后将会详细讨论,因而在此处对于这些话题我们将不予考虑。代码清单2-4给出了完整的代码:
代码清单2-4 Main.java
就是这些了!我们在大约10行Java代码中就完成了对iBATIS的配置,执行了SQL语句,并且打印了结果。以上就是一个功能完整的iBATIS应用所需要的全部Java代码。稍后,我们将对其进行改进,但是现在我们将继续讨论有关iBATIS配置的基础知识。
5.3 配置iBATIS(预览)
考虑到我们将在下一章中深入介绍如何配置iBATIS,所以此处我们将只是简单介绍一下。此处你不会找到有关配置选项的过多解释,但是我们将给出最重要的信息。
首先,让我们来研究SqlMapConfig.xml文件。它是使用iBATIS的起点,负责把所有的SQL映射文件组合在一起。代码清单2-5给出了我们的简单应用中使用的SqlMapConfig.xml文件。
代码清单2-5 最简单的iBATIS应用中的SQL映射配置
你可能已经猜到,我们正是在此配置文件中告诉iBATIS如何连接数据库,以及获取哪些SQL映射文件。由于这是一个XML文件,我们需要提供doctype和DTD用于验证(1)。SIMPLE是一个iBATIS内置事务处理器的别名(2)。我们需要为这个事务处理器提供JDBC驱动的名称、JDBC URL、以及允许你连接到数据库的用户名(username)和密码(password)。然后你将提供你的SQL映射文件(3)。此例中,我们只有一个SQL映射文件,但是你可以想要多少就提供多少个。该文件中你还可以做一些其他设置,我们将在下一章中详细介绍。
现在你已经看到了主配置文件,下面我们来看一下SqlMap.xml文件(代码清单2-6)。这个文件包含了我们将要运行的SQL语句。
代码清单2-6 最简单的SQL映射
代码清单2-6的XML中,我们接受了一个String类型的参数(parameterClass)作为GROUPNAME列的值,并且把结果类(resultClass)映射到了一个HashMap上。
警告:
我们并不推荐使用Map(例如,HashMap、TreeMap)作为域模型,但是这样做确实显示了iBATIS所提供的映射的灵活性。你并不总是需要映射到JavaBean——你可以直接映射到Map或者基本类型。
无论你是否相信,你现在已经看到了使用iBATIS所需要的所有代码和配置。我们故意将它分散开以便于印刷,但是即使如此,这些代码总共也只有大约50行,包括Java和XML。而且更重要的一点是,这50行代码中有45行都是有关配置的,这些配置在一个应用中只需要编写一次即可,而不需要针对每个语句都写一次。正如你在本章之前的例子中所见到的那样,使用JDBC最终需要对每条SQL语句都编写50行或者更多的代码。
5.4 构造应用
通常当构建一个大型应用时,你都会使用一些类似于Ant的工具来简化构建过程。由于本例中我们只有一个类,因此就不需要麻烦地为它创建一个Ant脚本了。为了编译此应用,你只需要在classpath上添加两个JAR文件:ibatis-common-2.jar和ibatis-sqlmap-2.jar,因此我们只要用命令行把它们输入给Java编译器即可:
javac -classpath <your-path>ibatis-common-2.jar;
<your-path>ibatis-sqlmap-2.jar Main.java
当然了,以上的代码应该在同一行中输入,并且你应该用JAR文件的实际路径来代替<your-path>。如果一切都顺利的话,编译器应该不会产生任何输出到屏幕上,而只是在当前目录上创建一个Main.class文件。
5.5 运行应用
在执行此应用时,我们还需要另外一些JAR文件,但也不是那么多。为了运行我们的应用,我们只需要在classpath上添加以下JAR文件即可:ibatis-common-2.jar、ibatis-sqlmap-2.jar、commons-logging.jar以及JDBC驱动(在此例中,这个驱动器就是mysql-connector-java.jar),因而下面应该输入以下这个命令:
java -classpath <your-path>;mysql-connector.jar;commons-logging.jar;
ibatis-common-2.jar;ibatis-sqlmap-2.jar;.Main
同样地,在编辑时以上代码必须在同一行中,同时应该用系统中的实际路径来代替<your-path>。
这个程序运行之后会告诉你选择出了多少条记录,然后将它们以一种以较粗糙的格式输出,类似如下:
iBATIS框架被设计得非常灵活。它可以是一个非常轻量简单的框架,只执行SQL并且返回数据,当然也可以被用来做其他更多的工作。
这种灵活性的关键之一在于对框架的正确配置。在下一章中,我们将讨论两种主要的配置文件类型,然后研究通过使用配置来处理复杂情况的一些模式。
注意:
配置文件都是标准的XML文档。这意味着如果你有一个时髦的XML编辑器,就可以用DTD(Document Type Definition)来验证你的文档是否存在语法错误,有时候甚至可以在编辑过程中提供代码提示和自动完成功能。
现在你已经看到了最简单形式的iBATIS。在我们继续讨论其他内容之前,先来讨论一下iBATIS的未来发展方向,这样你在使用它时就可以更加的有信心。
6 iBATIS未来的发展方向?
在过去几个月中,iBATIS获得了巨大的发展动力。作为结果,iBATIS小组发展壮大了,产品也得到了改进,我们也开始讨论支持新平台的问题了。下面我们将详细地讨论iBATIS未来的发展方向。
6.1 Apache软件基金会
近期,iBATIS已经成为了Apache软件基金会的一部分。我们之所以选择转向Apache,是因为我们相信他们的使命并且尊重他们的态度。Apache绝不仅仅是一堆服务器和基础设施的组合,它是一个系统,是开源软件真正的家。Apache更关注软件周边社区(即使用者社区),而不是软件背后的技术,因为如果没有社区,软件就是一个死的工程。
这对于iBATIS用户来说意味着,iBATIS并不是由某个单独的团体来指导,也不是依赖于某个单独的团体。iBATIS不属于任何个人——它属于整个社区。Apache能够始终保护iBATIS,并且确保它维持正确的方向。然而,Apache许可并没有像GPL might许可那样,限制对开源软件的使用。Apache许可并不是一个viral许可,这意味着你可以在商业环境中自由地使用这些软件,而不用担心需要遵守许多不合理的条件。
虽然Apache并不关注基础设施,但是它们确实拥有一些非常好的基础设施。目前iBATIS使用Subversion source control(SVN)进行版本控制,用Atlassian的JIRA来跟踪问题,用Atlassian的Confluence来协作撰写wiki文档,并且使用Apache的邮件列表服务器进行开发小组、用户以及一般社区之间的交流。
Apache拥有保护iBATIS所需要的一切,并且可以确保:只要仍然有人想要使用iBATIS,它就会在那儿。
6.2 更简单、更小、依赖性更少
和其他框架不同的是,iBATIS工程并不期望分枝出新的领域,也没有任何野心要解决所有问题。iBATIS是一个目标非常集中的工程,每一次发布新版本,我们都期望能使它更小、更简单,并且更少地依赖第三方库。
我们相信iBATIS还有许多创新的空间。iBATIS可以从很多新的技术和设计方法中获益,以便使其配置更加简练,也更容易使用。例如,C#和Java都内置了元数据(attribute,也可称为“标注(annotation)”)功能。在未来的版本中,iBATIS就有可能利用此功能来减少配置框架时所需的XML代码的数量。
在为iBATIS开发支持工具方面也还有许多事情可做。iBATIS的设计使得为其开发像IDE这样的图形化工具非常地容易。也可考虑创建支持从数据库框架(database schema)中直接生成iBATIS配置文件的工具,其实这一点上已经有相应的工具可以用了。你可以在我们的网页http://ibatis.apache.org上看到一些工具的示例。
6.3 更多的扩展点和插件
iBATIS已经有了许多扩展点。我们将在第12章中深入探讨有关扩展的问题。你可以实现你自己的事务处理器、数据源、缓存控制器(cache controller),以及其他。但是我们期望使得iBATIS更易于扩展。我们希望将JDBC架构的几乎每一层都设计为可扩展的,这将意味着你可以实现自己的ResultSet处理器和SQL执行引擎。这将帮助我们支持更复杂的系统,或者遗留系统以及私有系统。它也将使开发者能够更充分地利用特定数据库或应用服务器的定制特性。
6.4 支持更多的平台和语言
正如你在第1章和第2章中所看到的那样,我们已经在.NET和Java中讨论了iBATIS。本书的其余部分将主要关注Java版iBATIS的API,但是大部分的信息都是可以被转化成.NET平台的。另外,我们还将在附录中较详细讨论iBATIS.NET。实际上iBATIS也已经有Ruby实现了,但是Ruby是一种完全不同的语言,因此用Ruby实现的iBATIS也有很大的不同。本书中我们就不讨论其Ruby实现了。
除了Java和C#之外,iBATIS小组还在讨论用其他的语言来实现iBATIS,这些语言包括PHP 5和Python。我们相信iBATIS对于几乎任意一种无法使用或不愿使用底层数据库API和高层对象/关系映射工具的平台,都可以做出巨大的贡献。iBATIS可以帮助你找到折中的办法,并且允许你始终用一致的方式来实现所有的应用。
我们也曾经讨论过要起草一份规范,使用户可以更容易地把iBATIS移植到不同的平台上,并且确保合理的一致性。当然了,我们既希望iBATIS能够充分利用特定语言和平台的特性,也期望它们能有一定程度的相似性,以便确保它们都能被称为iBATIS,并且能够被熟悉另一种语言中的iBATIS的开发者一眼就辨认出来。
7 小结
在本章中,你已经了解到iBATIS是一个独特的数据映射器,它使用一种被称为SQL映射的方式将对象持久化到关系数据库中。iBATIS在Java和.NET两个平台上的实现始终是一致的,而在应用中始终采用一种一致的持久化方式也具有非常重要的意义。
在本章中,你还学习了iBATIS是如何工作的。通常,在后台iBATIS将运行编写好了的JDBC或ADO.NET代码,如手工编写这些代码将非常难以维护。我们发现,和JDBC相比,iBATIS代码更加简洁,也更易于编写。
我们还讨论了为什么iBATIS对于小型和大型商业应用来说都是非常合适的框架,尽管它的设计很简单。iBATIS具有很多支持企业级持久化需求的特性。如行处理器等特性可以允许高效地处理大型数据集,每次处理一条记录,这样就保证了不会耗尽系统的内存。
我们还讨论了iBATIS所以区别于其他竞争对手的一些很重要的特性,同时我们还构造了一个使用iBATIS的简单示例。这些特性包括:
l 简单性——iBATIS被广泛认为是最简单的一种持久化框架。
l 生产效率——简洁的代码和简单的配置使得使用iBATIS所需的代码量可以减少到了相应JDBC代码的62%。
l 性能——架构级性能增强,如联合查询的使用等,加速了数据的处理。
l 关注点的分离——iBATIS改进了应用的设计方式以确保未来的可维护性。
l 细化分工——iBATIS可以帮助细化分工,使得工作团队能够充分利用个人的专长。
l 可移植性——iBATIS可以用任何具有完备功能的编程语言来实现。
宣传了iBATIS的优点之后,我们也承认iBATIS并不是一颗“银弹”,因为没有任何框架是万能的。我们讨论了在哪些情况下使用iBATIS可能不是最完美的方案。例如,当你始终拥有对应用和数据库的完全控制权时,采用一个成熟的对象/关系映射工具可能就是更好的选择。另一方面,如果你的应用主要处理动态生成的SQL代码,直接使用JDBC可能就是更好的选择了。我们也提到了iBATIS主要是为关系数据库而设计的,因此如果你使用的是平板文件、XML、Excel表单,或者其他任何非关系数据库技术存储数据,那么你最好还是使用另一种完全不同的API。
最后,我们以对iBATIS未来发展的讨论结束本章。关于iBATIS的未来,开发小组有很多非常好的设计理念,同时Apache软件基金会将会确保始终有一个充满活力的社区能够支持iBATIS未来的发展。