ibatis 使用文档 (上篇)

(代码下载地址:http://download.csdn.net/detail/partner4java/4760043)

iBATIS一词来源于“internet”和“abatis”的组合,是一个基于Java的持久层框架。
创建于2002年,后很快加入了Apache,但是2010年又易主到google code,并改名为MyBatis。
本篇文章主要是基于iBATIS来进行展示,后面会再发一篇和MyBatis的对比。
(本文大多摘自《iBATIS in action》一书,若有时间学习此书,建议不要看本文--因为书中更详细,且本文可能存在技术点上的错误分析)

==================================================================================================
第1章 iBATIS的理念

(导读:本章主要介绍iBATIS框架的设计理念,可能会随带几个iBATIS的展示,目前不需要关心如何去书写或代码规范,只需要对概念有所了解即可)

SQL(Structured Query Language,结构化查询语言)已经存在很长一段时间了。而且在接下来的很长一段时间内还会继续存在。
iBATIS的建立正是基于这样的思想:关系数据库和SQL仍然很有价值,在整个产业范围内对SQL投资仍然是一个非常好的注意。
我们可能都曾有过这样的经历,应用程序的源代码(即使发展了很多版本)随着时间的流逝最终还是过时了,但他的数据库甚至是SQL本身却仍然很有价值。
在某些情况下我们也会看到一个应用程序已经被其他的语句重写了,但背后的SQL和数据库却基本上保持不变。

正是基于这些原因,iBATIS并不试图去隐藏SQL或者避免使用SQL。
相反,正是iBATIS这个持久层框架广泛使用了SQL,他使得SQL更容易使用、更容易集成到现代的面向对象软件中。

混合型解决方案在IT领域同样被证明是非常有效的。iBATIS就是这样一个混合型的持久层解决方案。

一:探索iBATIS的根源
iBATIS是一个混合型解决方案。他吸取了SQL、老式存储过程(“两层应用程序”)、现代存储过程、内联SQL、动态SQL、ORM这些解决方案中最有价值的思想并将他们融会贯通。

iBATIS提供的与其他解决方案相同的优点:
-------------------------------------------------------------------------------------------------------------------------


iBATIS框架的核心价值:外部化SQL和封装SQL

二:外部化SQL
“总是将一个大系统设计为多个子系统,每个子系统的功能都相对集中”。
应该尽可能的降那些由不同的开发角色处理的任何分离开。
外部化将SQL从应用程序的源代码中分离出来,从而使得两者都更加清晰。
这样就保证了SQL语句与任何特定的语言或平台都想对的独立。
在以前的书写方式中,在代码中拼写SQL,容易引起空格等错误,特别是如果你有一条复杂的SQL语句。
这时iBATIS的一个主要优点就体现出来了:使用iBATIS你就拥有按照最自然的方式写SQL的能力。

select 
	name,
	age
from user
where address=#address#


三:封装化的SQL
计算机编程领域一个最古老的概念就是模块化。
iBATIS使用XML来封装SQL。

四:iBATIS适合应用在何处
几乎所有结构良好的软件都使用了分层设计。
iBATIS是一个持久层框架。持久层位于应用程序的业务逻辑层和数据库之间。这种分离非常重要,他保证了持久化策略不会混入业务逻辑代码,反之亦然。
这种分离的好处在于你的代码更将加容易维护,因为他允许对象模型的转化不依赖于数据库设计。

==================================================================================================
第2章 iBATIS是什么

(导读:本章主要介绍iBATIS框架是什么,并简单附带了示例,目前仍不需要关心如何去书写或代码规范,只需要对概念有所了解即可)

概述:
iBATIS就是我们通常所说的数据映射器(data mapper)。
所谓映射器层,是用于在对象和数据库之间搬运数据,同时保证对象、数据库以及映射器本身都相互独立。

iBATIS与O/RM不同,他不是直接把类映射为数据库表或者说把类的字段映射为数据库列,而是把SQL语句的参数和结果映射为类。

iBATIS在数据库和类之间建立了一个额外的间接层,这就为在类和数据库直接建立映射关系带来了更大的灵活性,使得不用改变数据库模型或者对象模型的情况下改变他们的映射关系成为可能。(这里的间接层就是SQL)

一:映射SQL语句(我们来观赏下iBATIS的简单映射方式)
任何一条SQL语句都可以看做是一组输入和输出。输入即参数(parameter),通常可以在SQL语句的WHERE子句中找到。输出是SELECT子句中指定的那些列。

iBATIS使用一个简单的XML描述符文件来映射SQL语句的输入和输出。

示例:

示例代码中包含一条SQL SELECT语句,他返回地址数据。
select * from user_account where groupname=#groupname#
然后在sql-map-config.xml中加入

	...
	



第六步:编写代码 -- iBATIS的具体调用
public static void main(String[] args) throws Exception {
	//先创建一个Reader,为读取的配置的封装
	Reader reader = Resources.getResourceAsReader("sql-map-config.xml");


	//iBATIS API的核心是SqlMapClient接口。
	//SqlMapClient大致相当于Hibernate的Session或者JPA的EntityManager,用于执行全部的数据访问操作。
	SqlMapClient sqlMap = SqlMapClientBuilder.buildSqlMapClient(reader);


	//queryForList第一个参数为我们定义的
		select * from user_account where groupname=#groupname#
	

元素:
除非别无选择,否则没人愿意输入像这样一个长串的名字:com.partner4java.demo.entity.Account。
元素允许定义别名,这样就可以直接用account来代替刚才的那个冗长的全限定类名了。

当在配置过程中定义account这个别名之后,就可以在任何时候使用他了,每当你必须提供一个数据类型时,都可以使用全限定类名或者别名来告诉iBATIS你想使用哪个数据。
iBATIS为若干类型定义了别名,以免除开发人员必须手工添加这些别名的麻烦。

==================================================================================================

阐述完基本概念和helloworld,我们开始进行详细学习。前面的内容不是很理解也没有问题,下面通过多写几个Demo,将会豁然开朗。

==================================================================================================
第4章 使用已映射语句

(导读:下面进行学习常用简单语句如何配置和执行 -- 或者说是剖析我们前面的hello)

一:从基础开始

问题1:我们Demo中的Account.xml文件,里面的 select * from user_account where groupname=#groupname#
public static void main(String[] args) throws Exception {
	Reader reader = Resources.getResourceAsReader("sql-map-config.xml");
	SqlMapClient sqlMap = SqlMapClientBuilder.buildSqlMapClient(reader);
	List list = sqlMap.queryForList("getAllUsers", "EMPLOYEE");
	for (int i = 0; i < list.size(); i++) {
		System.out.println(list.get(i));
	}


}

问题:iBATIS框架是如何处理该语句的?
首先,iBATIS将查找名为Account.getAllUsers的已映射语句,并把#groupname#占位符变换为一个预备语句参数,就是转换成我们JDBC中所用的"?"格式。


2.使用内联参数(用$做占位符)
使用内联参数的另一种方式就是使用替代($)语法,它可以用来把值直接插入到SQL语句之中(在该SQL语句被转变为参数化语句之前)。
但是使用这种方式时要非常小心,因为它可能使你暴漏给SQL注入,另外过度使用还可能造成性能问题。
Demo:
Reader reader = Resources.getResourceAsReader("sql-map-config.xml");
SqlMapClient sqlMap = SqlMapClientBuilder.buildSqlMapClient(reader);
List list = sqlMap.queryForList("getUsersByGroupName", "EMPLOYEE");
for (int i = 0; i < list.size(); i++) {
	System.out.println(list.get(i));
}

3.SQL注入简介
SQL注入攻击是指恶意的用户将特殊格式的数据传递给某个应用程序,以使该应用程序做一些不该做的事。
例如:上面的示例传入
test' or 1 like '1
如果我们这个参数是密码之类的信息,是不是别人就能很容易“猜到”了?

问题:我们hello中返回结果的各个字段并没有和JavaBean中的字段做对应啊?它是如何自动对应的呢?

4.自动结果映射
你可能已经注意到了,在所有我们给出的示例中都没有定义任何结果映射(result map),但是确实定义了结果类(result class)。
这种方式可行是因为iBATIS的自动结果映射机制,该机制会在已映射语句第一次被执行时,迅速的自动创建一个结果映射,然后将它应用于这条已映射语句。
可以有3种方式来使用这个特性:单列选择(single-column selection),固定多列选择(fixed-column list selection)和动态多列选择(dynamic-column list selection)。

单列选择 --
如果只想从某个查询中获取单例,就可以使用别名value作为一种快捷方式来完成此目的,这样就可以不需要定义复杂的结果映射了,当然你不定义别名也可以,只需要指定resultClass:




固定多列选择 -- 
如果需要查询多列,就可以使用自动结果映射来告诉iBATIS将列名作为bean的特性名,或者作为Map键。
当以这种方式映射到bean时,需要牢记一点:如果所选择的列在数据库中存在,但是不存在于你要映射的bean中,你将不会得到任何错误或警告,但是也得不到任何数据--这些数据只会静静的被忽略。
映射到Map对象时,也有相似的问题:尽管你仍然可以得到数据,但是这些数据不会在你所期望的地方。

动态多列选择 -- 
如果语句中被选择的那些字段列表可以在运行时改变,那么也可以使用动态结果映射。
(后面章节我们再具体说动态映射)

5.联结相关数据
有时候出于制作报表或者其他的什么目的,你可能想要把多个数据表联结起来,形成一个平板型结构。
iBATIS框架可以让你毫不费力地完成这项工作,因为它是将SQL语句映射为对象,而不是将数据库中的表映射为对象,所以映射表查询和映射多表查询几乎没有什么不同。


三:映射参数
映射参数 -- java代码传入SQL所需参数 和 xml中配置的SQL脚本里的传入参数 之间的对应关系。
有两种方式可以将参数映射到已映射语句中:内联映射(inline mapping)和外部映射(external mapping)。
使用内联参数映射意味着:告诉iBATIS关于你需要什么的暗示,然后就让它完成细节的处理。
但是外部参数映射则明确的多 -- 可以明确地告诉iBATIS你要它做些什么。

1.外部参数映射
使用外部参数映射时,可以指定多达6个属性。如果没有指定其中的某个属性,iBATIS就会用反射来尽可能的为其确定而合理的值,但是这么做比较费时并且可能不准确。
property -- 设定一个参数时,property属性用于指定JavaBean中某个特性的名字,或者指定作为参数传递给已映射语句的Map实例的某个键值对(Map entry)的键值。
此名字可以不只使用一次,具体根据它在语句中所需要的次数而定。

javaType -- 设定一个参数时,javaType属性用来显示指定要设置的参数的Java特性类型
通常这个类型可以通过反射从JavaBEan特性中推断出来,但是某些映射方式并不能为框架提供这样的类型。
在这种情况下,如果没有设置javaType,而框架又不能通过另外的方式确定类型,就会假定类型为Object

jdbcType -- 设定一个参数时,jdbcType属性用来显示指定参数的数据类型。一些jdbc驱动程序在进行某些特定操作时,如果没有显示提供列的类型信息,他们就不能识别出这些类的类型。
通常,jdbcType属性只有当某列允许被设置为空时才是必需的。

nullValue -- nullValue属性用来指定外发的控制替换。
也就是说,数据写入时,如果在待写入的JavaBean特性或Map键值对中检测到该替换值,就将空值写入到数据库(反过程亦然,即从数据库中读取一个控制时,则将相应的JavaBean字段或Map键值对的值设为该替换值)

mode -- 该属性专门用于支持存储过程

typeHandler -- 如果想要指定类型处理器(而不是让iBATIS根绝javaType和jdbcType属性来选择类型处理器),你可以指定typeHandler属性
通常,该属性用来提供自定义的类型处理器

按照我们前面的用法:

	insert into user_account(username,password,groupname ) values(#username#,#password#,#groupname#)

Reader reader = Resources.getResourceAsReader("sql-map-config.xml");
SqlMapClient sqlMap = SqlMapClientBuilder.buildSqlMapClient(reader);
sqlMap.insert("insertAccount", new Account("hello", "123", "EMPLOYEE"));

这是借助了默认的反射机制,我们还可以自己指定各种参数类型:




	insert into user_account(username,password,groupname ) values(?,?,?)

Reader reader = Resources.getResourceAsReader("sql-map-config.xml");
SqlMapClient sqlMap = SqlMapClientBuilder.buildSqlMapClient(reader);
sqlMap.insert("insertAccountMap", new Account(null, "789", null));


2.再论内联参数映射
除了使用最简单形式的内联参数映射,来告诉iBATIS我们想要在运行时带入到查询中的特性名称,也可以在内联参数映射中提供一些外部参数映射所允许的特性。
例如:jdbcType(数据库类型)以及nullValue(参数的空值占位符),只要用冒号将参数名、数据库类型和空值占位符分隔开即可。
当你的数据库中包含允许为空的列时,数据库类型通常是必须设置。如果你没有明确告诉iBATIS究竟使用何种数据库类型,那么iBATIS将默认地使用java.sql.Types.OTHER作为sqlType,但一些数据库却东程序是不允许这么做的。
Demo:

Reader reader = Resources.getResourceAsReader("sql-map-config.xml");
SqlMapClient sqlMap = SqlMapClientBuilder.buildSqlMapClient(reader);
List list = sqlMap.queryForList("getUsersByGroupName3", "%EMPLOYEE%");
for (int i = 0; i < list.size(); i++) {
	System.out.println(list.get(i));
}

3.基本类型参数
Java5中,你可以在任何地方传递基本类型参数。

4. JavaBean参数和Map参数
虽然bean参数和Map参数有些不同,但是使用他们时所用的语法是一致的。
这两者的不同在于:加载参数映射时,它们的行为是不相同的。这因为这点,bean可以提前告知我们错误--当访问一个不存在的特性。

四:使用内联结果映射和显示结果映射


问题:我们讲过了参数映射,hello里也使用了自动结果映射,但是当数据库字段和JavaBean属性名字不对应怎么办?如何收集结果呢?(生产代码通常情况下,我们数据库字段使用下划线分割单词,但是javabean属性是大小写字母替代下换线来分割单词。)
显示结果映射:
内联结果映射的确非常好,因为他们非常容易使用,并且在大多数情况下都能很顺利的完成工作。
iBATIS中的显示结果映射也同样有价值,因为它们可以提供更好的性能、更严格的配置验证,以及更加精确的行为。
显示结果映射中可用的属性:
property -- 设定一条结果映射时,property属性用于指定JavaBean中某个特性的名字,或者指定作为参数传递给已映射语句的Map实例的某个键值对的键值。
column -- 设定一条结果映射时,column属性用于提供ResultSet的列的名称
columnIndex -- 是一个可选字段,用于提供列的索引以代替ResultSet中的列名
jdbcType -- 设定一条结果映射时,jdbcType属性用于显示指定ResultSet列的数据库的列类型
javaType -- 设定一条结果映射时,javaType属性用来显示指定要设置特性的Java特性类型。
nullValue -- 设置一条结果映射时,nullValue属性用来替换数据库中的空值
select -- 设置一条结果映射时,select属性用于描述对象之间的关系,这样iBATIS就能自动地加载复杂的特定类型;该语句特性的值必须是另外一个已映射语句的名字。

1.基本类型结果
iBATIS能把结果映射为任意类型,但是由于它只返回Object实例,基本类型的值就必须以:简单的值包装、bean或者Map。

2.JavaBean结果和Map结果
对于领域数据我们推荐使用bean,而对已那些不那么关键并且更加动态的数据,我们推荐使用Map。

Demo:

Reader reader = Resources.getResourceAsReader("sql-map-config.xml");
SqlMapClient sqlMap = SqlMapClientBuilder.buildSqlMapClient(reader);
List list = sqlMap.queryForList("getUsersByGroupName4", "%EMPLOYEE%");
for (int i = 0; i < list.size(); i++) {
	System.out.println(list.get(i));
}


你可能感兴趣的:(ibatis,-,mybatis)