ibatis使用文档(上篇)

来源:互联网 发布:预算软件有哪几种 编辑:程序博客网 时间:2024/06/16 08:20

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的能力。

[sql] view plaincopy
  1. select   
  2.     name,  
  3.     age  
  4. from user  
  5. where address=#address#  


三:封装化的SQL
计算机编程领域一个最古老的概念就是模块化。
iBATIS使用XML来封装SQL。
[html] view plaincopy
  1. <select id="categoryById"   
  2.     parameterClass="string" resultClass="category">  
  3.     select categoryid,name,description  
  4.     from category  
  5.     where categoryid=#categoryId#  
  6. </select>  

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

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

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

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

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

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

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

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

示例:
[html] view plaincopy
  1. <select id="getAddress" parameterClass="int" resultClass="Address">  
  2.     select   
  3.         ADR_ID              as  id,  
  4.         ADR_DESCRIPTION     as  description  
  5.     from address  
  6.     where ADR_ID = #id#  
  7. </select>  

示例代码中包含一条SQL SELECT语句,他返回地址数据。
从<select>元素中可以看出一个Integer对象作为参数,该参数是通过WHERE子句中的#id#符号标记的。
结果是一个Address类的对象实例,假设Address类的所有字段的名与SELECT语句中指定的各个列的别名相同,会被自动映射为相应字段。
Address address = (Address)sqlMap.queryForObject("getAddress",new Integer(8));

SQL映射这个概念具有很好的可移植性,可应用于任何一个功能完备的编程语言。

二:iBATIS如何工作(上面简单示例是如何工作的呢?)
Address address = (Address)sqlMap.queryForObject("getAddress",new Integer(8));
这行代码会执行相应的SQL语句,设置其参数,并以一个真实的Java对象的形式作为结果返回。
SQL语句被“干干净净”地封装在Java代码之外的一个XML文件中。iBATIS负责管理所有的幕后资源。

三:为何使用iBATIS
简单性、生产效率、性能、关注点分离、明确分工、可移植性、开源和诚实。

四:何时不该使用iBATIS
1.当对数据库永远拥有完全控制权时
当你对数据库具有完全控制权时,就有充分的理由使用一个完全的对象/关系映射方案,如Hibernate。

2.当应用程序需要完全动态的SQL时

3.当没有使用关系数据库时

4.当iBATIS不起作用时

==================================================================================================
第3章 iBATIS HelloWorld

(导读:目前你只需要跟着我做每一步,能写个helloworld,至于具体每个配置是什么含义,后面章节我们会一一道来)

一:HelloWorld

我们创建一个依赖于架构的项目,在脑海里应该很快的想到应该需要几个重要步骤:导入相关jar包;配置需要配置文件;如果和数据库相关还需要创建相应数据库。

第一步:创建项目并导入相关jar
创建一个项目(建议创建一个Maven项目 -- eclipse中可安装maven插件即可,具体操作请查阅相关资料)
所需jar:
ibatis2-common.jar -- 共享的iBATIS类
该文件包含SQL映射框架和DAO框架中要用到的公共组件。
ibatis2-sqlmap.jar -- iBATIS的SQL映射类
该文件包含SQL映射框架的所有组件
ibatis2-dao.jar -- 该文件包含DAO框架的所有组件
mysql-connector-java -- 具体要根据你使用的数据库而定

如果你创建的是一个非Maven项目,可直接导入jar:
(下载地址)
http://search.maven.org/#search%7Cga%7C1%7Ca%3A%22ibatis2-common%22
http://search.maven.org/#search%7Cga%7C1%7Ca%3A%22ibatis2-dao%22
http://search.maven.org/#search%7Cga%7C1%7Ca%3A%22ibatis2-sqlmap%22
http://search.maven.org/#search%7Cga%7C1%7Cmysql-connector-java

Maven项目:
[html] view plaincopy
  1. <dependencies>  
  2.     <dependency>  
  3.         <groupId>com.ibatis</groupId>  
  4.         <artifactId>ibatis2-common</artifactId>  
  5.         <version>2.1.7.597</version>  
  6.     </dependency>  
  7.   
  8.   
  9.     <dependency>  
  10.         <groupId>com.ibatis</groupId>  
  11.         <artifactId>ibatis2-dao</artifactId>  
  12.         <version>2.1.7.597</version>  
  13.     </dependency>  
  14.   
  15.   
  16.     <dependency>  
  17.         <groupId>com.ibatis</groupId>  
  18.         <artifactId>ibatis2-sqlmap</artifactId>  
  19.         <version>2.1.7.597</version>  
  20.     </dependency>  
  21.   
  22.   
  23.     <dependency>  
  24.         <groupId>mysql</groupId>  
  25.         <artifactId>mysql-connector-java</artifactId>  
  26.         <version>5.1.21</version>  
  27.     </dependency>  
  28. </dependencies>  

第二步:创建配置文件
在我们的类路径下创建xml文件:sql-map-config.xml
这是一个主配置文件(大家想下是不是我们平时用到的框架也需要一个主的配置文件?iBAITS也不例外)

(你先考进去或对比敲进去,然后改下数据库配置 -- 后面会详细介绍各配置的作用)
[html] view plaincopy
  1. <?xml version="1.0" encoding="UTF-8" ?>  
  2.   
  3.   
  4. <!DOCTYPE sqlMapConfig PUBLIC "-//ibatis.apache.org//DTD SQL Map Config 2.0//EN"  
  5.     "http://ibatis.apache.org/dtd/sql-map-config-2.dtd">  
  6.   
  7.   
  8. <sqlMapConfig>  
  9.     <transactionManager type="JDBC">  
  10.         <!-- SIMPLE是一个iBATIS内置事务管理器的名字 -->  
  11.         <dataSource type="SIMPLE">  
  12.             <property value="com.mysql.jdbc.Driver" name="JDBC.Driver" />  
  13.             <property  
  14.                 value="jdbc:mysql://localhost:3306/ibatis_test?autoReconnect=true"  
  15.                 name="JDBC.ConnectionURL" />  
  16.             <property value="root" name="JDBC.Username" />  
  17.             <property value="123456" name="JDBC.Password" />  
  18.         </dataSource>  
  19.     </transactionManager>  
  20. </sqlMapConfig>  

第三步:创建表
我这里用的mysql
[sql] view plaincopy
  1. CREATE TABLE `user_account` (  
  2.   `userid` int(11) NOT NULL AUTO_INCREMENT,  
  3.   `username` varchar(20) DEFAULT NULL,  
  4.   `passwordvarchar(20) DEFAULT NULL,  
  5.   `groupname` varchar(20) DEFAULT NULL,  
  6.   PRIMARY KEY (`userid`)  
  7. ) ENGINE=InnoDB DEFAULT CHARSET=utf8;  
  8.   
  9.   
  10. INSERT INTO `user_account` (`userid`, `username`, `password`, `groupname`) VALUES   
  11.   (1, 'LMEADORS''PICKLE''EMPLOYEE'),  
  12.   (2, 'JDOE''TEST''EMPLOYEE');  

第四步:编写代码 -- 数据库对应的POJO
像Hibernate一样写个数据库对应的POJO
[java] view plaincopy
  1. public class Account implements Serializable {  
  2.     private int userid;  
  3.     private String username;  
  4.     private String password;  
  5.     private String groupname;  
  6. ...  

第五步:创建另一个SQL映射文件
我们是不是前面强调了很多次,iBATIS主要功能是把SQL和代码进行分离?所以,我们需要一个地方存放SQL。
这里我们继续创建一个xml,这个xml可与具体表对应,也可与具体业务对应,总之,它就是一组相关SQL存放的位置。

本实体具体创建Account.xml(我们现在也是把此文件放在了类路径)
继续考入或参考敲入到你的xml文件中
[html] view plaincopy
  1. <?xml version="1.0" encoding="UTF-8" ?>  
  2.   
  3.   
  4. <!DOCTYPE sqlMap PUBLIC "-//ibatis.apache.org//DTD SQL Map 2.0//EN"  
  5.     "http://ibatis.apache.org/dtd/sql-map-2.dtd">  
  6.   
  7.   
  8. <sqlMap namespace="Account">  
  9.     <!-- 给我们的返回类型定义了一个短名称 -- account  -->  
  10.     <typeAlias alias="account" type="com.partner4java.demo.entity.Account" />  
  11.       
  12.     <!-- 我们写了一个select,查询语句就是被<select>名称对应的标签所包围;parameterClass为我们的传入参数值类型(string为系统默认定义的String短名称);resultClass返回类型;然后就是id,没什么可说的,具体SQL总要有标识id。 -->  
  13.     <select id="getAllUsers" parameterClass="string" resultClass="account">  
  14.         select * from user_account where groupname=#groupname#  
  15.     </select>  
  16. </sqlMap>  

然后在sql-map-config.xml中加入
[html] view plaincopy
  1. <sqlMapConfig>  
  2.     ...  
  3.     <sqlMap resource="Account.xml"/>  
  4. </sqlMapConfig>  


第六步:编写代码 -- iBATIS的具体调用
[java] view plaincopy
  1. public static void main(String[] args) throws Exception {  
  2.     //先创建一个Reader,为读取的配置的封装  
  3.     Reader reader = Resources.getResourceAsReader("sql-map-config.xml");  
  4.   
  5.   
  6.     //iBATIS API的核心是SqlMapClient接口。  
  7.     //SqlMapClient大致相当于Hibernate的Session或者JPA的EntityManager,用于执行全部的数据访问操作。  
  8.     SqlMapClient sqlMap = SqlMapClientBuilder.buildSqlMapClient(reader);  
  9.   
  10.   
  11.     //queryForList第一个参数为我们定义的<select>的id,第二个为传入的查询参数#groupname#  
  12.     List list = sqlMap.queryForList("getAllUsers""EMPLOYEE");  
  13.   
  14.   
  15.     //对获取的结果遍历(我对Account的toString进行了重写)  
  16.     for (int i = 0; i < list.size(); i++) {  
  17.         System.out.println(list.get(i));  
  18.     }  
  19. }  

这样我们就完成了一个简单的iBATIS

二:简述SQL Map配置文件
(这里只是简述,后面章节会有详细介绍)
SqlMapConfig.xml文件位于最上方,我们在此文件中定义那些全局配置选项以及对各个独立SqlMap文件的引用。
SqlMap文件则用于定义那些已映射语句(mapped statement),这些已映射语句结合应用程序提供的输入,来完成与数据库的交互。

SQL Map配置文件:
SQL Map配置文件(就是前前面的SqlMapConfig.xml)是iBATIS配置的核心(因此也成为主配置文件)。从数据库连接到实际所用的SqlMap文件都是通过此文件中的配置提供给框架的。
我们来看一个SqlMapConfig.xml文件(比我们前面hello里面更加完整)
[html] view plaincopy
  1. <?xml version="1.0" encoding="UTF-8" ?>  
  2.   
  3.   
  4. <!DOCTYPE sqlMapConfig PUBLIC "-//ibatis.apache.org//DTD SQL Map Config 2.0//EN"  
  5.     "http://ibatis.apache.org/dtd/sql-map-config-2.dtd">  
  6.   
  7.   
  8. <sqlMapConfig>  
  9.   
  10.   
  11.   <properties resource="properties/database.properties"/>  
  12.     
  13.   <settings   
  14.     useStatementNamespaces="false"   
  15.     cacheModelsEnabled="true"   
  16.     enhancementEnabled="true"   
  17.     lazyLoadingEnabled="true"   
  18.     maxRequests="32"   
  19.     maxSessions="10"   
  20.     maxTransactions="5"  
  21.     />  
  22.       
  23.   <transactionManager type="JDBC">  
  24.     <dataSource type="SIMPLE">  
  25.       <property value="${driver}" name="JDBC.Driver"/>  
  26.       <property value="${url}" name="JDBC.ConnectionURL"/>  
  27.       <property value="${username}" name="JDBC.Username"/>  
  28.       <property value="${password}" name="JDBC.Password"/>  
  29.     </dataSource>  
  30.   </transactionManager>  
  31.   
  32.   
  33.   <sqlMap resource="org/apache/ibatis/jgamestore/persistence/sqlmapdao/sql/Account.xml"/>  
  34.   
  35.   
  36. </sqlMapConfig>  

settings为全局配置选项
transactionManager为事务管理器
最下面会存在很多sqlMap,是对各个Sql Map文件的引用

<properties>元素:
<properties>元素允许在主配置文件之外提供一个properties格式对应文件,从而使得主配置文件更加通用。这样对部署非常有用。
两个属性
resource--类路径上的一个资源
url -- 统一资源定位符
最后通过名称来引用这些属性。

<settings>元素:
<settings>元素添加若干属性来设置这些可选项。iBATIS有许多配置项可用,并且每个配置项对于这个SQLMap实例来说都是全局的。
1.lazyLoadingEnabled
延迟加载是一种只加载必要信息而推迟加载其他未明确请求的数据的技术。也就是说,除非绝对需要,否则应用程序加载的数据越少越好。
lazyLoadingEnabled配置项用于指定当存在相关联的已映射语句时,是否使用延迟加载。其有效值为true或false,默认值为true。
2.cacheModelsEnabled
数据告诉缓存是一种提高程序性能的技术,他基于近期使用过的数据往往很快又会被用到这样一个假设,将近期使用过的数据保存到内存中。
cacheModelsEnabled配置项用于指定是否想让iBATIS使用该技术。有效值也是true或false。
为了充分利用高速缓存技术,还必须为已映射语句配置高速缓存模型(后面会介绍)。
3.enhancementEnabled
enhancementEnabled用于指定是否使用cglib中那些已优化的类来提高延迟加载的性能。其有效值仍然是true或false,默认值为true。
当你运行增强,但是如果cglib不在类路径上,性能增强仍然会被悄悄的禁用。
4.useStatementNamespaces
useStatementNamespaces配置项用于告诉iBATIS,在引用已映射语句时,是否需要使用限定名(qualified name)。其有效值也为true或false,默认值为false。
也就是说,当你定义了SQL映射之后,就用该SQL映射名来限定这条已映射语句。
例如,假设你有一个名为Account的SQL映射,他包含名为insert、update等映射语句。那么当你想插入一个账户且在主配置文件中启用了useStatementNamespaces配置项时,就必须用Account.insert这个名字来调用这条已映射的语句。
通过使用命名空间,你就可以根据需要,创建任意数目名为insert的已映射语句(在其他映射文件中),而不会照成名字冲突。
虽然我们可以使用类似insertAccount这样的名字来完成相同的事,但是在面对大型系统时,使用命名空间将更有用,因为即使在已映射语句的组织毫无逻辑时,命名空间也可以帮助找到他们。
5.maxRequests(已废弃)
例如我们设置了maxRequests="32",这样我们的数据库一次最多只允许有32个请求出于活动状态。
6.maxSessions(已废弃)
会话(session)是一种线程级机制,用于跟踪关于一组相关事务和请求的信息。
maxSessions="10" 表示任何时候都只允许10个会话。
7.maxTransactions(已废弃)
事务(transaction)就是指数据库事务。
(如果确实要修改这些配置项,请确保maxRequests总是大于maxSessions,而maxSessions总是大于maxTransactions)

<transactionManager>元素:
由于iBATIS就是为了使数据库访问变得更加简单而设计的,因此他将为你处理所有的数据库事务。
使用iBATIS时,有哪些事务管理器实现类是可用的。可以考虑使用iBATIS那些预定义的事务管理器。
<transactionManager>元素的type属性就是用于指定应该使用哪个事务管理器的。
iBATIS提供了若干内建事务管理器实现:
JDBC用于提供简单的基于jdbc的事务管理。大多数情况下,使用这个事务管理器就足够了。
JTA用于在你的应用程序中提供基于容器的事务管理。
EXTERNAL用于提供非事务管理,并假定管理事务的是应用程序,而不是iBATIS

对于事务管理器,另一个可用的设置就是commitRequired属性,该属性可被设置为true或者false,默认是为false。
他主要用于那些要求在释放某个连接之前必须提交(commit)或者回退(rollback)的情况。
对于某些操作(例如选择和存储过程调用),通常并不需要事务,因此一般会将其忽略。
某些数据库驱动程序(例如Sybase驱动程序)不会轻易释放连接,直至该连接的每个已启动事务都已提交或回退。在这些情况下,就可以使用commitRequired属性来强制释放连接,即使在那些通常需要在一个事务中释放却没用释放的情况。

1.<property>元素
每个事务管理器都可以有不同的配置项。因此,iBATIS框架允许使用<property>元素来指定任意数目的键值对以提供给相应的事务管理器实现类。
2.<dataSource>元素
在java中,使用连接池的标准方法就是通过javax.sql.DataSource对象。
事务管理的<dataSource>元素有一个属性,用来告诉iBATIS他应该为其数据源工厂实例化并使用哪个类。
<dataSource>元素名字很容易仍人产生误解,因为实际上他并不是用来定义DataSource,而是用来定义DataSourceFactory实现类,iBATIS将用这个实现类来创建实际的DataSource。
iBATIS具有三种数据源工厂实现类:
SIMPLE即简单的数据源工厂。它用于配置那种内置有简单连接池的数据源,因此除了实际的JDBC驱动程序之外,该数据源工厂所需的其他东西都包含在iBATIS框架中。
DBCPDBCP数据源工厂用于使用Jakarta Commons数据库连接池实现
JNDIJNDI数据源工厂用于允许iBATIS共享通过JNDI定位的基于容器的数据源

<sqlMap>元素:
SqlMapConfig.xml文件的最后一部分就是我们配置<sqlMap>元素的地方。正是此处你开始真正了解到iBATIS可以为你做的大量繁重的工作。
他也是支持resource和url两种属性,分别用于将映射文件通过相对于类路径根路径和任意的URL值。

<typeHandler>元素:
在上面的示例中
iBATIS使用类型处理器(type handler)将数据从数据库特定的数据类型转换为应用程序中的数据类型,这样你就可以创建一个以一种尽可能透明的方式来使用数据库的应用程序。
类型处理器本质上就是一个翻译器(translator)--他将数据库返回的结果集合中的列“翻译”为相应的JavaBean中的字段。
如果自定义类型处理器,需要创建两个类:一个自定义类型处理器和一个类型处理器回调类。

三:简述SqlMap -- Account.xml
[html] view plaincopy
  1. <?xml version="1.0" encoding="UTF-8" ?>  
  2.   
  3.   
  4. <!DOCTYPE sqlMap PUBLIC "-//ibatis.apache.org//DTD SQL Map 2.0//EN"  
  5.     "http://ibatis.apache.org/dtd/sql-map-2.dtd">  
  6.   
  7.   
  8. <sqlMap namespace="Account">  
  9.   
  10.   
  11.     <typeAlias alias="account" type="com.partner4java.demo.entity.Account" />  
  12.       
  13.     <select id="getAllUsers" parameterClass="string" resultClass="account">  
  14.         select * from user_account where groupname=#groupname#  
  15.     </select>  
  16. </sqlMap>  

<typeAlias>元素:
除非别无选择,否则没人愿意输入像这样一个长串的名字:com.partner4java.demo.entity.Account。
<typeAlias>元素允许定义别名,这样就可以直接用account来代替刚才的那个冗长的全限定类名了。
<typeAlias alias="account" type="com.partner4java.demo.entity.Account" />
当在配置过程中定义account这个别名之后,就可以在任何时候使用他了,每当你必须提供一个数据类型时,都可以使用全限定类名或者别名来告诉iBATIS你想使用哪个数据。
iBATIS为若干类型定义了别名,以免除开发人员必须手工添加这些别名的麻烦。

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

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

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

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

一:从基础开始

问题1:我们Demo中的Account.xml文件,里面的<select>标签是如何选择的呢?
1.已映射语句的类型
已映射语句有多种类型,每种类型都有各自不同的用途、属性集以及子元素。
但一般来讲,最好使用与你要完成的任务相匹配的语句类型(例如,要插入数据应该使用<insert>语句,而不是使用<update>),虽然这似乎是理所当然的,但仍请您务必遵守。

除了已映射语句的类型之外,还包括另外两个通常用来创建已映射语句的元素:<sql>元素和<include>元素。
联合使用这两个元素能够创建可插入到已映射语句中的组件。当你想要复用复杂的SQL片段,却又不想复制它们时,就会发现上面这两个元素非常有用。

<sql>元素用于创建一个文本片段,而这些文本片段又可以组合起来以创建完整的SQL语句。(如图:代码清单4-1.jpg)

问题2:我们无论是否借助框架,或者借助其他ORM框架,对表的查询结果是不是要封装到Java对象中啊?

2.创建JavaBean
bean的构成 -- 本质上而言,JavaBean规范就是一组规则,用于定义Java开发可使用的组件。
这些规则使得工具创建者可以知道如何与我们在应用程序中所使用的组件进行交互。
规范可以看做是框架开发人员和应用程序开发人员的一个中间层公共语言。

问题3:有了存放结果的对象,那么如何查询结果呢?
3.iBATIS API的核心是SqlMapClient接口。

SqlMapClient大致相当于Hibernate的Session或者JPA的EntityManager,用于执行全部的数据访问操作。


核心工具类SqlMapClient接口有很多方法,我们来介绍几个核心方法:

queryForObject()方法 --
queryForObject()方法用于从数据库中获取一条记录,并把它放入到一个Java对象中。
它有以下两种签名:
queryForObject(String id, Object parameter)
queryForObject(String id, Object parameter,Object result)
第一种签名较为常用,只要所返回的对象有默认构造器(default constructor),它就能为你创建它(如果没有,就会抛出运行时异常)。
第二种签名接受一个将被用作返回值的对象 -- 运行已映射语句之后,该方法并不会创建一个新的对象,而是在该语句中设置特性。如果你请求的对象不能被轻易创建,那么这种方式非常有用。
使用queryForObject()方法时需要记住的是,如果查询返回了不止一行,该方法就会抛出异常,因此它总会检查以确保仅返回一行。

queryForList()方法 --
queryForList()方法用于从数据库中返回一行或多行,并把它放入到一个Java对象列表中,和queryForObject一样,该方法也有两个版本
queryForList(String id, Object parameter) throws java.sql.SQLException;
queryForList(String id, Object parameter, int skip, int max) throws java.sql.SQLException;
第一个版本的方法将已映射语句所返回的所有对象全部返回。而第二个版本的方法只返回其中的一部分--它将跳到skip参数所指定的位置上,并返回从查询结果开始的max行。

queryForMap()方法 --
queryForMap()方法用于从数据库中返回一行或多行组成的一个Java Map。
queryForMap(String id, Object parameter, String key) throws java.sql.SQLException;
queryForMap(String id, Object parameter, String key, String value) throws java.sql.SQLException;
第一个版本的方法将执行一个查询,并返回由一组Java对象组成的Map,其中这些对象的键值由key参数所指定的特性来标识,而值对象则为已映射语句返回的对象。
第二个版本的方法将返回一个类型的Map,但是这些对象将会是value参数所标识对象的特性。


二:使用select已映射语句
从数据库中获取数据是一个应用程序中最基本的操作之一。iBATIS框架使得编写大部分的SELEC语句都毫不费力,并且提供了很多特性,使得你几乎可以从数据库中得到任何想要的数据。

问题:我们前面SQL中包含了groupname=#groupname#,这么个东东,可以从结构上猜想这应该是传入参数的固定格式。那么具体如何定义和使用呢?
(两种方式#和$)
1.使用内联参数(用#做占位符)
内联参数(inline parameter)就是一种在已映射语句中添加查询条件的简单方式,你可以使用两个不同的方法来设置内联参数。
第一个方法是使用散列(#)符号。
[html] view plaincopy
  1. <sqlMap namespace="Account">  
  2.   
  3.   
  4.     <typeAlias alias="account" type="com.partner4java.demo.entity.Account" />  
  5.       
  6.     <select id="getAllUsers" parameterClass="string" resultClass="account">  
  7.         select * from user_account where groupname=#groupname#  
  8.     </select>  
  9. </sqlMap>  

[java] view plaincopy
  1. public static void main(String[] args) throws Exception {  
  2.     Reader reader = Resources.getResourceAsReader("sql-map-config.xml");  
  3.     SqlMapClient sqlMap = SqlMapClientBuilder.buildSqlMapClient(reader);  
  4.     List list = sqlMap.queryForList("getAllUsers""EMPLOYEE");  
  5.     for (int i = 0; i < list.size(); i++) {  
  6.         System.out.println(list.get(i));  
  7.     }  
  8.   
  9.   
  10. }  

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


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

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:
[html] view plaincopy
  1. <select id="getAllAcoountIds" resultClass="int">  
  2.     select userid as value from user_account  
  3. </select>  
  4.   
  5.   
  6. <select id="getAllAcoountIds" resultClass="int">  
  7.     select userid from user_account  
  8. </select>  

固定多列选择 -- 
如果需要查询多列,就可以使用自动结果映射来告诉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属性
通常,该属性用来提供自定义的类型处理器

按照我们前面的用法:
[html] view plaincopy
  1. <insert id="insertAccount" parameterClass="account">  
  2.     insert into user_account(username,password,groupname ) values(#username#,#password#,#groupname#)  
  3. </insert>  

[java] view plaincopy
  1. Reader reader = Resources.getResourceAsReader("sql-map-config.xml");  
  2. SqlMapClient sqlMap = SqlMapClientBuilder.buildSqlMapClient(reader);  
  3. sqlMap.insert("insertAccount"new Account("hello""123""EMPLOYEE"));  

这是借助了默认的反射机制,我们还可以自己指定各种参数类型:
[html] view plaincopy
  1. <parameterMap class="account" id="accountMap">  
  2.     <parameter property="username" nullValue="hello" jdbcType="VARCHAR"/>  
  3.     <parameter property="password" nullValue="123" jdbcType="VARCHAR"/>  
  4.     <parameter property="groupname" nullValue="123" jdbcType="EMPLOYEE"/>  
  5. </parameterMap>  
  6.   
  7.   
  8. <insert id="insertAccountMap" parameterMap="accountMap">  
  9.     insert into user_account(username,password,groupname ) values(?,?,?)  
  10. </insert>  

[java] view plaincopy
  1. Reader reader = Resources.getResourceAsReader("sql-map-config.xml");  
  2. SqlMapClient sqlMap = SqlMapClientBuilder.buildSqlMapClient(reader);  
  3. sqlMap.insert("insertAccountMap"new Account(null"789"null));  


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

[java] view plaincopy
  1. Reader reader = Resources.getResourceAsReader("sql-map-config.xml");  
  2. SqlMapClient sqlMap = SqlMapClientBuilder.buildSqlMapClient(reader);  
  3. List list = sqlMap.queryForList("getUsersByGroupName3""%EMPLOYEE%");  
  4. for (int i = 0; i < list.size(); i++) {  
  5.     System.out.println(list.get(i));  
  6. }  

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:
[html] view plaincopy
  1. <resultMap class="account" id="accountRes">  
  2.     <result property="username2" column="username" nullValue="hello" jdbcType="VARCHAR"/>  
  3.     <result property="password" column="password" nullValue="123" jdbcType="VARCHAR"/>  
  4.     <result property="groupname" column="groupname" nullValue="123" jdbcType="EMPLOYEE"/>  
  5. </resultMap>  
  6. <select id="getUsersByGroupName4" parameterClass="string" resultMap="accountRes">  
  7.     select * from user_account where groupname like #groupname#  
  8. </select>  
[java] view plaincopy
  1. Reader reader = Resources.getResourceAsReader("sql-map-config.xml");  
  2. SqlMapClient sqlMap = SqlMapClientBuilder.buildSqlMapClient(reader);  
  3. List list = sqlMap.queryForList("getUsersByGroupName4""%EMPLOYEE%");  
  4. for (int i = 0; i < list.size(); i++) {  
  5.     System.out.println(list.get(i));  
  6. }  
原创粉丝点击