随着大数据技术的兴起和快速发展,人们更多的开始关注HDFS、HBase、Hive等技术。但是谈到强一致性,我们又不得不回归现实,只能继续沿用RDBMS存储强一致性的数据。我们日常接触到的绝大多数的应用(从App到游戏,从互联网应用到SAP)都是基于数据的,应用程序执行的过程也是不断进行数据处理的过程,而应用的设计是面向对象的,数据库更多是面向数据的,两种不同思维造成系统理解、设计的复杂性。同时随着业务复杂度的不断提高,对数据库的依赖也不断增加,逐渐造成系统与数据库耦合过于紧密。
随着面向对象、系统解耦的要求,我们希望能有一种技术实现将数据库结构转化成易于理解的程序数据结构。通过对程序数据的处理,转化为对数据库的操作。而这正是ORM(对象关系映射object Relational Mapping)的一个理论基础。
ORM方法论基于三个核心原则:
简单性:以最基本的形式建模数据。
传达性:数据库结构被任何人都能理解的语言文档化。
精确性:基于数据模型创建正确标准化了的结构。
一、ORM与IBatis
早些年在Java领域有一个非常知名的框架SSH(Spring + Struts +Hibernate)。他们各自承担这不同的职责,实现了表现层、业务层和数据持久化层分离,降低了各层耦合。其中Hibernate则主要是实现了业务层与数据化持久层的解耦。Hibernate建立的理论基础是ORM。它是建立将面向对象的数据转化和操作映射为数据持久化操作的一种技术。
在ORM的领域中除了Hibernate还有很多其他框架。例如EntityFrameword、IBatis等。我们今天要介绍的就是IBatis,这个被称为“半自动化”的ORM框架。
要介绍IBatis首先要说一下“半自动化”这个定语。之所有成IBatis为“半自动化”,是相对于Hibernate而言的。Hibernate可以实现不编写Sql语句实现将业务数据操作转化为数据库操作。IBatis没有像Hibernate那样进行全面的封装,它并没有抛弃Sql语句,甚至它不会减少Sql语句的编写量,它只是提供了一种将Sql语句与系统分离的方式,这也给我们留下了足够了空间发挥Sql的强大语法。
二、IBatis原理
IBatis的基本原理的理解可以从理解官方文档中的这个图开始
IBatis以SqlMap为核心,将输入参数、输出结果进行持久化语句与CLR类型的转化。输入参数类(Parameter object)经过SqlMap中设置的数据处理方式,并结合持久化数据处理方式(ADO.NET),从而产生输出结果类(Result object)。对于.NET应用程序业务处理来说,实现了类的方法处理,从而实现了应用逻辑与数据持久化的隔离。
从上图可以看出,输入参数Parameter object和输出结果Result object均支持集合类型、基本类型、值类型。其中间为核心的数据转化过程。数据转化过程是通过XML配置进行约束的。本文章为技术实践文章,因此重点为IBatis相关配置文件的使用。
三、IBatis配置文件
1、SqlMap.config
IBatis基本运行环境的核心配置文件为SqlMap.config文件。它类似于应用程序的App.config和Web.config。IBatis的其他文件均是通过此配置文件加载到系统中的。基本的SqlMap.config如下图所示:
SqlMap.config主要包括几部分:Settings、providers、database、sqlMaps
Settings:主要进行IBatis全局基础配置,它包括三个配置项
节点名 |
说明 |
默认值 |
useStatementNamespaces |
是否使用语句命名空间,这里的命名空间指的是映射文件中sqlMap节点的namespace属性。即如果该参数设为"true", 语句调用时需追加命名空间。 |
FALSE |
cacheModelsEnabled |
配置是否启用IBatis的配置项缓存机制 |
TRUE |
validateSqlMap |
配置是否启用SqlMapConfig.xsd schema验证映射文件 |
FALSE |
其中useStatementNamespaces是在系统环境中可能需要应用的。当值为“true”调用语句时需要添加其配置文件头中命名空间名称。例如
当useStatementNamespaces="true",调用时则需要通过名称“Complex.ComplexMap”,如果为false则通过名称"ComplexMap"进行调用。
Providers:配置数据驱动提供类配置文件的路径和文件名。
此配置中对应的文件中描述了多种数据驱动方式,通过配置可以保证IBatis支持市面上主流的数据(如Oracle\MsSql\MySql\sqlite\access等)。如需更换数据库,需要将配置文件中相应启动器的Enabled设置为“true”,并修改Database节中的配置即可。
Database:主要用来进行数据库驱动器配置和数据库连接字符串的配置。
provider的值应与providers配置文件中的name对应,并需要将providers配置文件中enabled设置为“true”。
dataSource的值为数据库连接字符串。为了更好的匹配连接字符,减少修改连接字符串的复杂度,可采用properties进行预定义处理。
sqlMaps:可以在配置节中添加XML映射文件的位置,以指定项目内所包含的所有映射文件。引用xml文件有三种方式
参数 |
说明 |
resource |
指定数据驱动配置文件从项目的根目录进行加载,如resource="providers.config" |
url |
指定数据驱动配置文件从文件的绝对路径进行加载,如url="c:\IBatis\Resources\providers.config" -或者- url="file://c:\IBatis\Resources\providers.config" |
embedded |
指定数据驱动配置文件可以作为程序集的资源文件进行加载,如embedded="Resources.providers.config, MyApp.Data" |
配置文件中还有一些其他的配置方式(如properties、alias、typeHandlers),这里就不一一介绍。
2、SqlMap.XML
SqlMap主要包括三部分,入参配置(Parameter)、返回结果配置(Result)、数据操作Sql配置(statements)。
parameter
用于配置入参格式,通过配置传入到statements中,parameter可以用过parameterClass或parameterMap两种方式传入。
parameterClass可配置为应用程序类别名,将相应的类实例传入到IBatis框架,通过其属性名作为SqlMap语句匹配元素进行配置,从而生成相应的Sql语句。
parameterMap可以对parameterClass进行扩展,从而实现空值转化、字段匹配等功能,通过配置的方式实现对空值、名称匹配等的处理。
Result
Resul也包括两种形式,resultClass和resultMap。resultClass配置可以将返回值映射为设定的类的实例,可以将查询结果等映射到相应的类中。
resultMap对resultClass扩展,可以设置数据查询字段与类数据字段的对应关系。
属性 |
说明 |
parameterMap |
参数映射,需结合parameterMap节点对映射关系加以定义,对于存储过程之外的statement而言,建议使用parameterClass作为参数配置方式,一方面避免了参数映射配置工作,另一方面其性能表现更加出色 |
parameterClass |
参数类。指定了参数类型的完整类名(包括命名空间),可以通过别名避免每次书写冗长的类名 |
resultMap |
结果映射,需结合resultMap节点对映射关系加以定义 |
resultClass |
结果类。指定了结果类型的完整类名(包括命名空间),可以通过别名避免每次书写冗长的类名 |
其中parameterMap和resultMap格式类似,主要包含如下属性:
属性 |
说明 |
property |
指定类中的一个属性 |
column |
定义的参数名称 |
direction |
用于声明存储过程的参数方向(input,output,inputoutput) |
dbType |
用于指定property映射到数据库中的数据类型 |
type |
用于为参数的对象指定CLR类型 |
nullValue |
指定在property为何值时,将会在存储数据时候,替换为null,这是经常会被用到的 |
size |
用于指定最大值 |
注:parameter和result都会涉及到类的属性,按照C#语言特性,属性等均是区分大小写的,因此在进行XML配置时,需要特别注意。
Statements
IBatis进行类和Sql进行相互转化的核心。他主要由id、parameter、result、动态Sql组成,前面初步介绍了id、parameter、result,以下终端介绍动态Sql语句。
为了更灵活的进行Sql语句匹配,IBatis进行了定义了多个运算符。
运算符 |
条件 |
说明 |
例程 |
isEqual |
二元条件 |
相等 |
<isEqual prepend="and" property="StartDate" compareValue="25/12/2004"> |
isNotEqual |
二元条件 |
不相等 |
<isNotEqual prepend="AND" property="year" compareValue="0"> |
isGreaterEqual |
二元条件 |
大于等于静态值 |
<isGreaterEqual compareValue="3" > |
isGreaterThan |
二元条件 |
大于 |
<isGreaterThan prepend="AND" property="Id" compareValue="0" > |
isLessEqual |
二元条件 |
小于等于 |
<isLessEqual compareValue="3" > |
isLessThan |
二元条件 |
小于 |
<isLessThan compareValue="3" > |
isNotEmpty |
一元条件 |
是否不为 null 或不为空 |
<isNotEmpty prepend="and" property="LastName" > |
isEmpty |
一元条件 |
是否为 null或空 |
|
isNotNull |
一元条件 |
检查属性是否不为 null。 |
<isNotNull prepend="AND" property="FirstName"> |
isNotParameterPresent |
|
检查是否不存在参数对象 |
<isNotParameterPresent prepend=”AND”> |
isNotPropertyAvailable |
一元条件 |
检查是否不存在该属性 |
|
isNull |
一元条件 |
检查属性是否为 null。 |
|
isParameterPresent |
|
检查是否存在参数对象(不为 null)。 |
|
isPropertyAvailable |
一元条件 |
检查是否存在该属性 |
|
iterate |
|
|
运算符的使用主要是针对输入参数的。
二元运算符
<isEqual property="name" compareValue="1" prepend="and"> a1= 'abc' </isEqual>
输入参数name属性的值等于1时,将在sql中组合 a1= 'abc',否则不进行Sql组合。
类似isNotEqual、isGreaterEqual、isGreaterThan、isLessEqual、isLessThan等均为类似的用法。
一元运算符
<isEmpty property="name" prepend="and"> a1= 'abc' </isEqual>
输入参数name属性的值为空时,将在sql中组合 a1= 'abc',否则不进行Sql组合。
数组运算符
将数组转为化sql语句的一种方式,例如
<iterate property="Ids" open="(" close=")" conjunction="," =""> #Ids[]# </iterate>
将数组转化为类似于“(1,2,3,4,5)”的Sql语句。
通过一系列的配置我们将程序的一个方法或一个对数据库的操作转化为一个SqlMap.Xml中的配置,方法入参转化为parameter,方法出参转化为result,而方法名转化为id,从而实现了面向对象的业务方法转化为数据库操作。
IBatis除了以上语法要点,还包括一些其他语法例如extends、缓存等。完整的语法支持,保证了IBatis对绝大多数场景的支持。本文在很多知识点只是进行了简单的说明,远远没有展示IBatis的全貌。只有通过不断的学习积累,并灵活应用才能发挥其强大的配置功能,才能更好的发挥IBatis的功能,实现真正的业务与数据的分离。