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

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


三:封装化的SQL
计算机编程领域一个最古老的概念就是模块化。
iBATIS使用XML来封装SQL。
[html]  view plain copy
  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 plain copy
  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 plain copy
  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 plain copy
  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 plain copy
  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 plain copy
  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 plain copy
  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 plain copy
  1. <sqlMapConfig>  
  2.     ...  
  3.     <sqlMap resource="Account.xml"/>  
  4. </sqlMapConfig>  


第六步:编写代码 -- iBATIS的具体调用
[java]  view plain copy
  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 plain copy
  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框架中。
DBCP DBCP数据源工厂用于使用Jakarta Commons数据库连接池实现
JNDI JNDI数据源工厂用于允许iBATIS共享通过JNDI定位的基于容器的数据源

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

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

三:简述SqlMap -- Account.xml
[html]  view plain copy
  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 plain copy
  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 plain copy
  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 plain copy
  1. <select id="getUsersByGroupName" parameterClass="string" resultClass="account">  
  2.     select * from user_account where groupname like '%$groupname$%'  
  3. </select>  
[java]  view plain copy
  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 plain copy
  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 plain copy
  1. <insert id="insertAccount" parameterClass="account">  
  2.     insert into user_account(username,password,groupname ) values(#username#,#password#,#groupname#)  
  3. </insert>  

[java]  view plain copy
  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 plain copy
  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 plain copy
  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 plain copy
  1. <select id="getUsersByGroupName3" resultClass="account">  
  2.     select * from user_account where groupname like #groupname,jdbcType=VARCHAR#  
  3. </select>  

[java]  view plain copy
  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 plain copy
  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 plain copy
  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. }  第5章 使用高级查询技术

    一:用已映射语句关联对象


    问题:如果你用过Hibernate或JPA,会想到entity(实体对象 -- 数据库对应JavaBean)之间可能存在关联关系。如一对一、多对多等。伴随就出现了关联获取技术,我们iBATIS如何做到关联获取呢?

    使用iBATIS可以根据相关联的对象来定义数据模型,并且让iBATIS立即加载到它们。
    例如:
    假设你有一个数据库,其中Account记录和Order记录存在关联,建立起这些关联关系之后,请求Account记录时,就会同时获得所有关联的Order对象。

    使用起来非常简单,大体通过以下步骤:
    第一步:在我们的JavaBean中建立对应关系
    [java]  view plain copy
    1. public class Order implements Serializable {  
    2.     private static final long serialVersionUID = -7307764485708148107L;  
    3.   
    4.   
    5.     private Integer orderId;  
    6.     private String orderAddress;  
    7. ...  
    8.   
    9.   
    10. public class Account implements Serializable {  
    11.     private static final long serialVersionUID = 3337778507086494766L;  
    12.   
    13.   
    14.     private Integer accountId;  
    15.     private String username;  
    16.     //建立了一个包含关联关系  
    17.     private List<Order> orders = new LinkedList<Order>();  
    18. ...  



    第二步:创建表(我用的MySQL)
    [sql]  view plain copy
    1. CREATE TABLE `orders` (  
    2.   `order_id` int(11) NOT NULL AUTO_INCREMENT,  
    3.   `order_address` varchar(20) DEFAULT NULL,  
    4.   `account_id` int(11) DEFAULT NULL,  
    5.   PRIMARY KEY (`order_id`)  
    6. ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;  
    7.   
    8.   
    9. CREATE TABLE `account` (  
    10.   `account_id` int(11) NOT NULL AUTO_INCREMENT,  
    11.   `username` varchar(20) DEFAULT NULL,  
    12.   PRIMARY KEY (`account_id`)  
    13. ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;  
    14.   
    15.   
    16. INSERT INTO `account` (`account_id`, `username`) VALUES   
    17.   (1, 'hello'),  
    18.   (2, 'world');  
    19.   
    20.   
    21. INSERT INTO `orders` (`order_id`, `order_address`, `account_id`) VALUES   
    22.   (1, 'hello1', 1),  
    23.   (2, 'hello2', 1);  


    第三步:在SqlMap中(Account.xml中)添加关联获取关系
    主要在resultMap中做了手脚,实现方式很简单:
    1.书写,我们关联获取时被调用的用于获取关联数据的<select>;被调取的用于获取关联数据的select中(也就是getOrderList中)参数使用#value#(固定格式)。
    2.包含关联关系的resultMap标签中,除了添加自己本身表中对应的result,额外添加对应关联属性的result标签。
    3.对应关联属性的result标签中,select属性值为被调取的用于获取关联数据的select标签的id。
    4.对应关联属性的result标签中,column属性值为代码调取获取数据的<select>中“主表”的关联字段名称。
    (<result property="orders" column="account_id" select="getOrderList" />)

    [html]  view plain copy
    1. <sqlMap namespace="Account">  
    2.     <typeAlias alias="account" type="com.partner4java.demo1.bean.Account" />  
    3.     <typeAlias alias="order" type="com.partner4java.demo1.bean.Order" />  
    4.   
    5.   
    6.     <!-- 简单关联方案 -->  
    7.     <resultMap class="account" id="accountMap">  
    8.         <result property="accountId" column="account_id" />  
    9.         <result property="username" column="username" />  
    10.         <!-- 通过select来获取的值放入orders;select需要一个关联参数,为本处column -->  
    11.         <result property="orders" column="account_id" select="getOrderList" />  
    12.     </resultMap>  
    13.   
    14.   
    15.     <resultMap class="order" id="orderMap">  
    16.         <result property="orderId" column="order_id" />  
    17.         <result property="orderAddress" column="order_address" />  
    18.     </resultMap>  
    19.   
    20.   
    21.     <select id="getAccount" resultMap="accountMap">  
    22.         select * from account  
    23.     </select>  
    24.   
    25.   
    26.     <select id="getOrderList" resultMap="orderMap">  
    27.         select * from orders where  
    28.         account_id = #value#  
    29.     </select>  
    30. </sqlMap>  


    第四步:执行代码
    [java]  view plain copy
    1. public static void main(String[] args) throws Exception {  
    2.     Reader reader = Resources.getResourceAsReader("sql-map-config.xml");  
    3.     SqlMapClient sqlMapClient = SqlMapClientBuilder  
    4.             .buildSqlMapClient(reader);  
    5.     List<Account> accounts = sqlMapClient.queryForList("getAccount"null);  
    6.     for(Account account:accounts){  
    7.         System.out.println(account);  
    8.     }  
    9. }  
    10. 打印:  
    11. Account [accountId=1, username=hello, orders=[Order [orderId=1, orderAddress=hello1], Order [orderId=2, orderAddress=hello2]]]  
    12. Account [accountId=2, username=world, orders=[]]  

    延迟加载:
    要使用延迟加载,需要编辑SqlMapConfig.xml文件,通过在<setting>元素中将lazyLoadingEnabled属性改为true来启动它。
    如果想要使用延迟加载的cglib增强版,则必须下载并将其添加到应用程序的类路径中,同时也必须将<setting>元素中的enhancementEnabled属性改为true。
    必须注意的是,这是一个全局设置,因此如果启用了这些特性,SQL映射中所有的已映射语句都将会使用延迟加载。

    问题:你是否会揣摩到上面的查询方式会出现“N+1”问题呢,那么如何解决“N+1”问题?
    避免N+1问题:
    [html]  view plain copy
    1. <!-- N + 1查询方案,注意每个resultMap都添加了一个groupBy -->  
    2. <resultMap class="order" id="orderJMap" groupBy="orders.order_id">  
    3.     <result property="orderId" column="order_id" />  
    4.     <result property="orderAddress" column="order_address" />  
    5. </resultMap>  
    6.   
    7.   
    8. <resultMap class="account" id="accountJMap" groupBy="account.account_id">  
    9.     <result property="accountId" column="account_id" />  
    10.     <result property="username" column="username" />  
    11.     <!-- 这里的resultMap为我们上面对order的定义 -->  
    12.     <result property="orders" resultMap="Account.orderJMap" />  
    13. </resultMap>  
    14.   
    15.   
    16. <select id="getAccountJ" resultMap="accountJMap">  
    17.     select  
    18.     account.account_id,account.username,orders.order_id,orders.order_address  
    19.     from account join orders on account.account_id = orders.account_id  
    20.     order  
    21.     by account.account_id,orders.order_id  
    22. </select>  

    [java]  view plain copy
    1. public static void main(String[] args) throws Exception {  
    2.     Reader reader = Resources.getResourceAsReader("sql-map-config.xml");  
    3.     SqlMapClient sqlMapClient = SqlMapClientBuilder  
    4.             .buildSqlMapClient(reader);  
    5.     List<Account> accounts = sqlMapClient.queryForList("getAccountJ"null);  
    6.     for(Account account:accounts){  
    7.         System.out.println(account);  
    8.     }  
    9. }  

    但是这种方式会丢失不存在order的Account,可以使用left join。


    问题:当我执行的不是一个简单insert、update时如何选择标签?
    iBATIS框架的设计意图就是要灵活。当无法使用其他类型的已映射语句时,也许就可以使用<statement>已映射语句。
    1.使用语句类型和DDL
    <statement>类型的已映射语句有点奇怪,它和其他类型(例如<insert>)的已映射语句不同的地方就是,它没有对应的方法可以调用。
    这就暗示了,我们不鼓励使用<statement>类型的已映射语句,只有在别无选择的情况下才可以考虑使用它。

    <statement id="dropTableTest">
    drop table test;
    </statement>

    sqlMapClient.update("dropTableTest", null);


    ==================================================================================================
    第6章 事务

    一:事务是什么


    用最简单的话来说,事务就是一项通常包含若干步骤的工作单元,这些步骤必须作为整体来执行,无论成功还是失败。
    也就是说,如果一个事务中的任何一个步骤失败了,那么所有其他步骤必须回滚,以保证数据仍处于一致的状态。

    示例:就是常用的两个账户的转账的问题。

    支持事务的数据库需要具备的特性通常称为ACID:原子性(atomicity)、一致性(consistency)、隔离性(isolation)和持久性(durability)。


    二:自动事务


    与JDBC还有所谓的“自动提交”模式不同,iBATIS处理的只有事务,它根本就没有在一个事务之工作的概念(除非你数据库不支持事务),因此它对“自动提交”的支持其实完全是间接的。
    作为“自动提交”的替代,iBATIS支持所有的自动事务。
    自动事务允许使用单个的方法调用来运行单个更新语句活查询语句,而完全不用关心如何划分事务。


    三:局部事务
    所谓局部事务,它仅仅涉及一个应用程序、一种资源(例如关系数据库),并且一次只能处理一个事务。

    首先配置:
    [html]  view plain copy
    1. <transactionManager type="JDBC">  
    2.     <!-- SIMPLE是一个iBATIS内置事务管理器的名字 -->  
    3.     <dataSource type="SIMPLE">  
    4. ...  

    [java]  view plain copy
    1. public static void main(String[] args) throws Exception {  
    2.     Reader reader = Resources.getResourceAsReader("sql-map-config.xml");  
    3.     SqlMapClient sqlMapClient = SqlMapClientBuilder  
    4.             .buildSqlMapClient(reader);  
    5.       
    6.     //学过jdbc的,是不是很容易理解啊?  
    7.     sqlMapClient.startTransaction();  
    8.       
    9.     long being = System.currentTimeMillis();  
    10.     try {  
    11.         sqlMapClient.startBatch();  
    12.         for(int i=0;i<1000;i++){  
    13.             Account account = new Account("en5" + i, "o5""EMPLOYEE");  
    14.             sqlMapClient.insert("insertAccount", account);  
    15.         }  
    16.         sqlMapClient.executeBatch();  
    17.         sqlMapClient.commitTransaction();  
    18.     } catch (Exception e) {  
    19.         e.printStackTrace();  
    20.     }finally{  
    21.         sqlMapClient.endTransaction();  
    22.     }  
    23.     System.out.println("time:" + (System.currentTimeMillis() - being));  
    24.       
    25. }  

    定制事务:
    我们也可以获取一个conn,然后使用conn手工管理事务,不过我们建议在基于conn管理事务的基础上使用sqlMapClient来执行SQL操作。
    [java]  view plain copy
    1. public static void main(String[] args) throws Exception {  
    2.     Reader reader = Resources.getResourceAsReader("sql-map-config.xml");  
    3.     SqlMapClient sqlMapClient = SqlMapClientBuilder.buildSqlMapClient(reader);  
    4.     Connection conn = null;  
    5.     SqlMapSession session = null;  
    6.     try {  
    7.         conn = sqlMapClient.getDataSource().getConnection();  
    8.         conn.setAutoCommit(false);  
    9.         session = sqlMapClient.openSession(conn);  
    10.         session.insert("insertAccount"new Account("hello""123""EMPLOYEE"));  
    11.           
    12.         conn.commit();  
    13.     } catch (Exception e) {  
    14.         if(conn != null) conn.rollback();  
    15.         e.printStackTrace();  
    16.     }finally{  
    17.         if(session != null){  
    18.             session.close();  
    19.         }  
    20.         if(conn != null){  
    21.             conn.close();  
    22.         }  
    23.     }  
    24. }  

    (局部事务就不多说了,你自己打一遍就明白了)

    ==================================================================================================
    第7章 使用动态SQL

    一:先来个hello

    [html]  view plain copy
    1. <select id="queryAccount" resultClass="account" parameterClass="string">  
    2.     select * from user_account   
    3.     <!-- 就多了一个这种标签,看这标签的起名是不是很像我们Junit里的断言啊? -->  
    4.     <isNotNull>  
    5.         where groupname = #value#  
    6.     </isNotNull>  
    7. </select>   

    [java]  view plain copy
    1. public static void main(String[] args) throws Exception {  
    2.     Reader reader = Resources.getResourceAsReader("sql-map-config.xml");  
    3.     SqlMapClient sqlMapClient = SqlMapClientBuilder  
    4.             .buildSqlMapClient(reader);  
    5.     List<Account> accounts = sqlMapClient  
    6.             .queryForList("queryAccount""EMPLOYEE");  
    7.     for (Account account : accounts) {  
    8.         System.out.println(account);  
    9.     }  
    10. }  


    也可以:使用<dynamic>标签作为父标签
    <dynamic>标签不像其他动态SQL标签,它不会去评测(evaluate)任何值或状态。它通常只是使用prepend属性,该属性值将作为前缀被加到<dynamic>标签的内容体之前。
    如果<dynamic>标签的内容体经iBATIS处理后没有产生任何文本,那么prepend值将被忽略。
    [html]  view plain copy
    1. <select id="queryAccount" resultClass="account" parameterClass="string">  
    2.     select * from user_account   
    3.     <dynamic>  
    4.         <isNotNull>  
    5.             where groupname = #value#  
    6.         </isNotNull>  
    7.     </dynamic>  
    8. </select>  

    二:熟悉动态标签

    所有标签分为5类:
    <dynamic>标签、二元标签、一元标签、参数标签以及<iterate>标签。

    先看一下所有的动态SQL标签都有的属性和行为。
    open、close:无条件地将其属性值放在标签的结果内容的开始处和结束处。
    prepend:除了dynamic之外,prepend属性在所有其他标签中的功能也都是一样的。<dynamic>标签在内容体的结果SQL非空时,总是将其prepend属性值添加为该结果SQL的前缀。

    只有当你想要向据诶过内容体使用open、close或prepend值时,才必须使用<dynamic>标签。


    <dynamic>标签:
    <dynamic>标签是最顶层标签;这意味着它不能被嵌套。该标签用来换分一个动态的SQL片段。
    <dynamic>标签的属性:
    prepend(可选的):该值用于作为前缀添加到标签的结果内容体前。但是当标签的结果内容体为空时,prepend值将不起作用。
    open(可选的):该值用于作为前缀添加到标签的结果内容体前。但是如果结果内容体为空,open将不会附加到前面。open值将在prepend属性值被添加前缀先被添加前缀。
    close(可选的):该值用于作为后缀附加到标签的结果内容体后。如果标签的结果内容体为空,close值将不起作用。

    iBATIS二元标签:
    二元标签(binary tag)用于将参数特性的某个值同另外一个值或者参数特性做比较。
    如果比较结果为true,那么结果SQL中就包含其内容体。
    所有的二元标签都共享compareProperty特性、compareValue属性。
    property属性用于设置被比较的基本类型值,而compareProperty属性和compareValue属性则用于设置比较的参考值。
    compareProperty属性会指定参数对象中的一个特性,该字段的取值会作为比较时的参数。
    compareValue属性则会指定一个静态值,用于比较的基本类型值。
    二元标签的属性:
    property(必需的):参数对象中用于同compareProperty或者compareValue想比较的特性。
    prepend(可选的):该值用于作为前缀附加到标签的结果内容体前。只有以下情况prepend值不会被加为前缀:当标签的结果内容体为空时;如果该标签是第一个产生内容体,且它被嵌套在一个removeFirstPrepend属性被设置为true的父标签中时。
    open(可选的):该值用于作为前缀添加到标签的结果内容体前。如果标签的结果内容体为空,open值将不会被附加到其前面。open值将在prepend属性值被添加为前缀之前先被添加前缀。
    close(可选的):该值用于作为后缀附加到标签结果内容体后。如果标签的结果内容体为空,则close值将不起作用。
    removeFirstPrepend(可选的):该值用于确定第一个嵌套的内容生产标签是否移除其prepend值(prepend是可选属性)。
    compareProperty(如果没有指定compareValue,则它是必需的):该值指定参数对象中的一个特性用来同property属性所指定的特性相比较。
    compareValue(如果没有指定compareProperty,则它是必需的):该值指定一个静态比较值用于同property属性所指定的特性相比较。

    二元动态标签:
    <isEqual>:将property属性同compareProperty属性或compareValue属性相比较,确定他们是否相同。
    <isNotEqual>:将property属性同compareProperty属性或compareValue属性相比较,确定他们是否不同。
    <isGreaterThan>:确定property属性是否大于compareProperty属性或compareValue属性。
    <isGreaterEqual>:确定property属性是否大于等于compareProperty属性或compareValue属性。
    <isLessThan>:确定property属性是否小于compareProperty属性或compareValue属性。
    <isLessEqual>:确定property属性是否小于等于compareProperty属性或compareValue属性。

    iBATIS一元标签:
    一元标签(unary tag)用于直接考察参数对象中某个bean特性的状态,而不是与其他进行比较。
    如果参数对象的状态结果为真,那么结果SQL中就会包含其内容体。
    所有的一元标签都共享property属性。一元标签的property属性用于指定参数对象上用来考察状态的特性。

    一元标签属性:
    property(必需的):参数对象中用于状态比较的特性。
    prepend(可选的):该值用于作为前缀附加到标签的结果内容体前。只有以下情况prepend值不会被加为前缀:当标签的结果内容体为空时;如果该标签是第一个产生内容体,且它被嵌套在一个removeFirstPrepend属性被设置为true的父标签中时。
    open(可选的):该值用于作为前缀,添加到结果内容体前。如果结果内容体为空,open值将不会被附加到其前面。open值将在prepend属性值被添加前缀之前先被添加前缀。
    close(可选的):该值用于作为后缀附加到标签的结果内容体后。如果结果内容体为空,则close值将不起作用。
    removeFirstPrepend(可选的):该属性值用于决定第一个产生内容的嵌套子标签是否移除其prepend值。

    一元标签:
    <isPropertyAvailable>:确定参数对象中是是否存在所指定的字段。对于bean,它寻找一个特性;而对于map,它寻找一个键。
    <isNotPropertyAvailable>:确定参数中是否不存在所指定的字段。对于bean,它寻找一个特性;而对于map,它寻找一个键。
    <isNull>:确定所指定的字段是否为空。对于bean,它寻找获取方法特性的返回值;而对于map,它寻找一个键,若这个键不存在,则返回true。
    <isNotNull>:确定所指定的字段是否为非空。对于bean,它寻找获取方法特性的返回值;而对于map,它寻找一个键,若这个键不存在,则返回false。
    <isEmpty>:确定所指定的字段是否为空、空字符串、空集合或者空的String.valueOf()。
    <isNotEmpty>:确定所指定的字段是否为非空、非空字符串、非空集合或者非空的String.valueOf()。

    iBATIS参数标签:
    考虑到iBATIS允许定义没有参数的已映射语句。
    参数标签(parameter tag)就是用来检查某个特定参数是否被传递给了已映射语句。
    参数标签的属性和前面大同小异。
    <isParameterPresent>:确定参数对象是否出现。
    <isNotParameterPresent>:确定参数对象是否不存在。

    iBATIS<iterate>标签:
    <iterate>标签以一个集合或数组类型的特性作为其property属性值,iBATIS通过遍历这个集合(数组)来从一组值中重复产生某种SQL小片段。
    这些小片段以conjunction属性值作为分隔符连接起来,从而形成一个有意义的SQL语句片段,open属性值将作为所呈现的值列表的前缀,close属性值将作为所呈现的值列表的后缀,最终形体形成一个完成合法的SQL。
    <iterate>标签属性:
    conjunction(可选的):该值用于连接iBATIS遍历集合(数组)时重复产生那些SQL小片段。
    其它属性基本一致。

    ==================================================================================================
    第8章 使用高速缓存提高性能

    (导读:建议你看的同事自己动手练,有什么疑问自己用各种方式试出来)
    (测试的建议:想看下是不是缓存,可在两次查询中做一个线程等待,然后去修改数据库,等待结束后,看数据是否改变,当然前提是你的缓存时间长于你的两次打印时间间隔,且修改工作在等待过程中完成)

    一:一个简单的iBATIS高速缓存示例

    iBATIS的强健且简单的高速缓存机制是完全基于配置的,因此避免了直接使用高速缓存的负担。
    [html]  view plain copy
    1. <!-- type="MEMORY",指定其高速缓存类型为MEMORY,把查询结果直接存储在内存中。 -->  
    2. <cacheModel type="MEMORY" id="categoryCache">  
    3.     <!-- flushOnExecute标签用于指定当某个特定高速缓存被访问时,其存储结果将被清除。 -->  
    4.     <flushOnExecute statement="insert" />  
    5.     <flushOnExecute statement="update" />  
    6.     <flushOnExecute statement="delete" />  
    7.     <!-- 每一种类型的高速缓存模型都有一些专用于它自己配置的特性,property标签就是用于完成这些专用特性的设置的。那么属性指定该高速缓存模型将要设置的特性的名称,value指定该预定义特性的值。 -->  
    8.     <property name="reference-type" value="WEAK" />  
    9. </cacheModel>  
    10.   
    11.   
    12. <select id="queryAccount" resultClass="account" parameterClass="string"  
    13.     cacheModel="categoryCache">  
    14.     select * from user_account  
    15.     <dynamic>  
    16.         <isNotEmpty>  
    17.             where groupname = #value#  
    18.         </isNotEmpty>  
    19.     </dynamic>  
    20. </select>  

    二:理解高速缓存模型

    有关高速缓存模型,最简单的描述就是,它是一种高速缓存配置。或者更确切的说,它是定义所有的iBATIS高速缓存实现的基础。
    高速缓存模型的配置是在SQL Map配置文件中,通过<cacheModel>标签来定义。
    <cacheModel>标签属性:
    id(必需的):该值用于指定一个唯一的ID,便于为需要使用此高速缓存模型所配置的高速缓存的查询已映射语句所引用。
    Type(必需的):此属性用于指定高数缓存模型所配置的高速缓存的类型。其有效值包括MEMORY、LRU、FIFO和OSCACHE。该属性也可取值为某个自定义CacheController实现的全限定类名。
    readOnly(可选的):将该值设置为true,就表示高速缓存将仅仅被用作只读高速缓存。
    serialize(可选的):该属性值指定在读取高速缓存内容时是否要进行“深复制”

    1.type属性 -- 内置的各种高速缓存模型类型:
    MEMORY:这个模型简单的将高速缓存保存在内存中,直至垃圾收集器将它移除。
    FIFO:这个模型中,高速缓存的数据量是固定的,使用“先进先出(first in first out)”算法来移除高速缓存中的数据。
    LRU:这个模型中,高速缓存的数据量也是固定的,使用“最近最少使用(least recently used)”算法来移除高速缓存中的数据。
    OSCACHE:这个模型使用OpenSymphony高速缓存

    要使用何种高速缓存实现,是通过将它们相应的默认关键字(MEMORY、LRU、FIFO以及OSCACHE)添加到<cacheModel>标签的type属性来指定的。
    也可以自己实现CacheController接口,然后在type属性中指定其全限定类名,以提供一套自己的高速缓存方案。

    2.readOnly属性:
    <cacheModel>标签提供了一个readOnly属性。
    该属性仅仅是一个为高速缓存模型提供指令的指示器,用于告诉高速缓存模型应该如何检索和保存已告诉缓存对象。
    该属性设置为true,并不能保证从高速缓存中检索出的对象其内容不被改变。
    指定一个高速缓存为只读时,也就是告诉高速缓存模型允许其返回对存在于高速缓存中的某个对象的引用,因为该对象将不会被正在请求它的应用程序所改变。
    如果readOnly属性设置为false,就可以确保不会出现多个用户同时访问某个已高速缓存的对象的同一引用实例的情况。

    3.serialize属性:
    serialize属性用于指示已高速缓存对象应该如何返回。
    当该属性被设置为true时,高速缓存中所请求的每个对象都将作为一个深拷贝被返回。
    这就意味着从高速缓存中检索出来的对象只具有相同的值,但并不是同一个实例。
    这就可以确保存储在高速缓存中的实际数据永远不会被改变。
    需要注意的是,此处所谓的串行化并不是我们所学的“序列化”,它并不是把数据串行化到硬盘上。
    这里的串行化是基于内存的串行化,用于创建内存中已高速缓存对象的深拷贝。

    4.联合使用readOnly属性和serialize属性:
    它们看上去在功能上视乎存在一些重叠,事实上,它们需要紧密协同才能正常工作。
    readOnly serialize结果原因
    true false可以最快速的检索出已高速缓存的对象。返回已高速缓存对象的一个共享实例,若使用不当可能会导致问题。
    false true  好 能快速检索出已高速缓存对象。返回已高速缓存对象的一个深拷贝。
    false false  警告 对于此种组合,高速缓存仅仅对调用线程的会话的声明周期有关,且不能被其他线程所使用。
    true true  坏 这种组合同readOnly=false而serialize=true的组合作用一致,否则它在语义上没有任何意义。

    以上两个属性的默认组合是readOnly=true和serizalize=false。  


    三:如何使用高速缓存模型中的标签
    1.高速缓存的清除
    <flushOnExecute> -- 定义查询已映射语句,其执行将引起相关高速缓存的清除
    <flushInterval> -- 定义一个时间间隔,高速缓存将以此间隔定期清除

    <flushOnExecute>标签:
    只有一个属性statement,当某条已映射语句执行时,将触发相应高速缓存的清除。
    当你在需要必须更新高速缓存以保证与数据库一致是尤其有用。

    <flushInterval>标签:
    除了时间之外它没有任何配置上的依赖性。
    每个一定的时间间隔就会清除一次高速缓存。

    2.设置高速缓存模型实现的特性:
    <property>标签的属性name和value,都是必需的。
    它们用来构建一个可传递给高速缓存模型组件以供其初始化的Properties对象。

    四:高速缓存模型的类型
    MEMORY:
    MEMORY高速缓存是一种基于引用的高速缓存。
    高速缓存中的每个对象都赋予一个引用类型。此引用类型为垃圾收集器提供了线索,指导它如何处理相应的对象。
    引用类型:
    WEAK -- 将很快的废弃高速缓存的对象。这种引用不会阻止对象被垃圾收集器收集。它仅仅提供一种方式来访问高速缓存中的对象,该对象在垃圾收集器的第一遍收集中就会被移除。(默认)如果因为某种原因GC比较频繁,那么会带来频繁访问数据库的问题。
    SOFT -- 除非确定需要更多的内存,否则垃圾收集器始终不会收集对象。SOFT引用也确保不会超过内存限制,和WEAK相比,其数据库访问频率会低些。
    STRONG -- 其中的已高速缓存对象永远不会被废弃,除非到达了指定清除时间间隔。
    通过<property name="reference-type" value="WEAK" />来指定期望使用的引用类型。

    LRU:
    使用最近最少使用策略来管理高速缓存。
    只有当高速缓存超过指定大小限制约束条件时,才会废弃最近最少被访问的对象。
    大小限制定义了高速缓存中可以包含的对象数目。
    <property name="size" value="200" />

    FIFO:
    才用先进先出的管理策略。
    用法和收集点同上。
    (<property name="size" value="200" />)

    OSCACHE:
    需要依赖OSCache的jar。并放入OSCache需要的配置文件。

    ==================================================================================================
    第9章 结合Spring

    先从配置文件下手,然后书写我们的service,最后调用测试

    创建工程,我们Maven配置如下:
    pom.xml
    [html]  view plain copy
    1. <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
    2.     xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">  
    3.     <modelVersion>4.0.0</modelVersion>  
    4.     <groupId>com.partner4java.spring</groupId>  
    5.     <artifactId>5spring</artifactId>  
    6.     <version>0.0.1-SNAPSHOT</version>  
    7.   
    8.   
    9.     <properties>  
    10.         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>  
    11.         <spring.version>3.1.1.RELEASE</spring.version>  
    12.         <ibatis.version>2.1.7.597</ibatis.version>  
    13.     </properties>  
    14.   
    15.   
    16.     <dependencies>  
    17.         <dependency>  
    18.             <groupId>org.springframework</groupId>  
    19.             <artifactId>spring-context</artifactId>  
    20.             <version>${spring.version}</version>  
    21.         </dependency>  
    22.         <dependency>  
    23.             <groupId>org.springframework</groupId>  
    24.             <artifactId>spring-web</artifactId>  
    25.             <version>${spring.version}</version>  
    26.         </dependency>  
    27.         <dependency>  
    28.             <groupId>org.springframework</groupId>  
    29.             <artifactId>spring-aop</artifactId>  
    30.             <version>${spring.version}</version>  
    31.         </dependency>  
    32.         <dependency>  
    33.             <groupId>org.springframework</groupId>  
    34.             <artifactId>spring-orm</artifactId>  
    35.             <version>${spring.version}</version>  
    36.         </dependency>  
    37.   
    38.   
    39.         <dependency>  
    40.             <groupId>org.apache.ibatis</groupId>  
    41.             <artifactId>ibatis-sqlmap</artifactId>  
    42.             <version>2.3.4.726</version>  
    43.         </dependency>  
    44.         <dependency>  
    45.             <groupId>org.apache.ibatis</groupId>  
    46.             <artifactId>ibatis-core</artifactId>  
    47.             <version>3.0</version>  
    48.         </dependency>  
    49.   
    50.   
    51.         <dependency>  
    52.             <groupId>mysql</groupId>  
    53.             <artifactId>mysql-connector-java</artifactId>  
    54.             <version>5.1.21</version>  
    55.         </dependency>  
    56.         <dependency>  
    57.             <groupId>c3p0</groupId>  
    58.             <artifactId>c3p0</artifactId>  
    59.             <version>0.9.1.2</version>  
    60.         </dependency>  
    61.   
    62.   
    63.         <dependency>  
    64.             <groupId>cglib</groupId>  
    65.             <artifactId>cglib</artifactId>  
    66.             <version>2.2.2</version>  
    67.         </dependency>  
    68.   
    69.   
    70.         <dependency>  
    71.             <groupId>org.aspectj</groupId>  
    72.             <artifactId>aspectjweaver</artifactId>  
    73.             <version>1.6.9</version>  
    74.         </dependency>  
    75.   
    76.   
    77.         <dependency>  
    78.             <groupId>junit</groupId>  
    79.             <artifactId>junit</artifactId>  
    80.             <version>4.10</version>  
    81.             <scope>test</scope>  
    82.         </dependency>  
    83.     </dependencies>  
    84.   
    85.   
    86. </project>  

    第一步:创建数据库相关配置文件

    在类路径下创建:jdbc-c3p0.properties
    [html]  view plain copy
    1. driverClass=com.mysql.jdbc.Driver  
    2. jdbcUrl=jdbc:mysql://localhost:3306/ibatis_test?useUnicode=true&characterEncoding=UTF-8  
    3. user=root  
    4. password=123456  
    5.   
    6.   
    7. #初始化时获取的连接数,取值应在minPoolSize与maxPoolSize之间。Default: 3  
    8. initialPoolSize=1  
    9.   
    10.   
    11. #连接池中保留的最小连接数  
    12. minPoolSize=1  
    13.   
    14.   
    15. #连接池中保留的最大连接数。Default: 15  
    16. maxPoolSize=300  
    17.   
    18.   
    19. #最大空闲时间,60秒内未使用则连接被丢弃。若为0则永不丢弃。Default: 0  
    20. maxIdleTime=60  
    21.   
    22.   
    23. #当连接池中的连接耗尽的时候c3p0一次同时获取的连接数。Default: 3  
    24. acquireIncrement=5  
    25.   
    26.   
    27. #每60秒检查所有连接池中的空闲连接。Default: 0  
    28. idleConnectionTestPeriod=120  
    29.   
    30.   
    31. #定义在从数据库获取新连接失败后重复尝试的次数。Default: 30  
    32. #acquireRetryAttempts=30  
    33.   
    34.   
    35. #两次连接中间隔时间,单位毫秒。Default: 1000  
    36. #acquireRetryDelay=1000  
    37.   
    38.   
    39. #连接关闭时默认将所有未提交的操作回滚。Default: false  
    40. #autoCommitOnClose=false  
    41.   
    42.   
    43. #JDBC的标准参数,用以控制数据源内加载的PreparedStatements数量。但由于预缓存的statements   
    44. #  属于单个connection而不是整个连接池。所以设置这个参数需要考虑到多方面的因素。   
    45. #  如果maxStatements与maxStatementsPerConnection均为0,则缓存被关闭。Default: 0  
    46. #maxStatements=100  
    47.   
    48.   
    49. #maxStatementsPerConnection定义了连接池内单个连接所拥有的最大缓存statements数。Default: 0   
    50. #maxStatementsPerConnection=  
    51.   
    52.   
    53. #c3p0是异步操作的,缓慢的JDBC操作通过帮助进程完成。扩展这些操作可以有效的提升性能   
    54. # 通过多线程实现多个操作同时被执行。Default: 3  
    55. #numHelperThreads=3  
    56.   
    57.   
    58. #当用户调用getConnection()时使root用户成为去获取连接的用户。主要用于连接池连接非c3p0   
    59. #  的数据源时。Default: null  
    60. #overrideDefaultUser=root  
    61.   
    62.   
    63. #与overrideDefaultUser参数对应使用的一个参数。Default: null  
    64. #overrideDefaultPassword=  
    65.   
    66.   
    67. #定义所有连接测试都执行的测试语句。在使用连接测试的情况下这个一显著提高测试速度。注意:   
    68. #  测试的表必须在初始数据源的时候就存在。Default: null  
    69. #preferredTestQuery=select id from test where id=1  
    70.   
    71.   
    72. #用户修改系统配置参数执行前最多等待300秒。Default: 300  
    73. #propertyCycle=300  
    74.   
    75.   
    76. #因性能消耗大请只在需要的时候使用它。如果设为true那么在每个connection提交的   
    77. #  时候都将校验其有效性。建议使用idleConnectionTestPeriod或automaticTestTable   
    78. #  等方法来提升连接测试的性能。Default: false  
    79. #testConnectionOnCheckout=false  
    80.   
    81.   
    82. #如果设为true那么在取得连接的同时将校验连接的有效性。Default: false  
    83. #testConnectionOnCheckin=true  
    84.   
    85.   
    86. #c3p0将建一张名为Test的空表,并使用其自带的查询语句进行测试。如果定义了这个参数那么   
    87. #属性preferredTestQuery将被忽略。你不能在这张Test表上进行任何操作,它将只供c3p0测试   
    88. #使用。Default: null  
    89. #automaticTestTable=Test  
    90.   
    91.   
    92. #获取连接失败将会引起所有等待连接池来获取连接的线程抛出异常。但是数据源仍有效   
    93. #  保留,并在下次调用getConnection()的时候继续尝试获取连接。如果设为true,那么在尝试   
    94. #  获取连接失败后该数据源将申明已断开并永久关闭。Default: false  
    95. #breakAfterAcquireFailure=false  
    96.   
    97.   
    98. #当连接池用完时客户端调用getConnection()后等待获取新连接的时间,超时后将抛出   
    99. #  SQLException,如设为0则无限期等待。单位毫秒。Default: 0  
    100. #checkoutTimeout=5000  
    101.   
    102.   
    103. #通过实现ConnectionTester或QueryConnectionTester的类来测试连接。类名需制定全路径。   
    104. #  Default: com.mchange.v2.c3p0.impl.DefaultConnectionTester  
    105. #connectionTesterClassName=  
    106.   
    107.   
    108. #指定c3p0 libraries的路径,如果(通常都是这样)在本地即可获得那么无需设置,默认null即可   
    109. #  Default: null  
    110. #factoryClassLocation=  
    111.   
    112.   
    113. #maxConnectionAge=400  

    第二步:创建我们Spring的DataSource(不多说,不懂去查阅Spring相关资料)

    创建文件datasource-c3p0.xml,放入类路径下的META-INF/spring中
    [html]  view plain copy
    1. <?xml version="1.0" encoding="GBK"?>  
    2. <beans xmlns="http://www.springframework.org/schema/beans"  
    3.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"  
    4.     xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"  
    5.     xsi:schemaLocation="http://www.springframework.org/schema/beans  
    6.            http://www.springframework.org/schema/beans/spring-beans-2.5.xsd  
    7.            http://www.springframework.org/schema/context  
    8.            http://www.springframework.org/schema/context/spring-context-2.5.xsd  
    9.            http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd  
    10.            http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">  
    11.       
    12.     <context:property-placeholder location="classpath:jdbc-c3p0.properties" />  
    13.     <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">  
    14.         <property name="driverClass" value="${driverClass}"/>  
    15.         <property name="jdbcUrl" value="${jdbcUrl}"/>  
    16.         <property name="user" value="${user}"/>  
    17.         <property name="password" value="${password}"/>  
    18.         <property name="initialPoolSize" value="${initialPoolSize}"/>  
    19.         <property name="minPoolSize" value="${minPoolSize}"/>   
    20.         <property name="maxPoolSize" value="${maxPoolSize}"/>  
    21.         <property name="maxIdleTime" value="${maxIdleTime}"/>   
    22.         <property name="acquireIncrement" value="${acquireIncrement}"/>     
    23.         <property name="idleConnectionTestPeriod" value="${idleConnectionTestPeriod}"/>  
    24.     </bean>  
    25.       
    26.       
    27. </beans>  

     第三步:创建我们的JavaBean
     
    [java]  view plain copy
    1. public class Account implements Serializable {  
    2.     private static final long serialVersionUID = -6876471972027832806L;  
    3.     private int userid;  
    4.     private String username;  
    5.     private String password;  
    6.     private String groupname;  
    7. ...  

    第四步:创建SqlMap
    创建文件Account.xml放入类路径下的ibatis文件夹中
    [html]  view plain copy
    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.     <typeAlias alias="account" type="com.partner4java.demo.entity.Account" />  
    10.   
    11.   
    12.     <select id="queryAccount" resultClass="account" parameterClass="string">  
    13.         select * from user_account  
    14.         <dynamic>  
    15.             <isNotEmpty>  
    16.                 where groupname = #value#  
    17.             </isNotEmpty>  
    18.         </dynamic>  
    19.         order by userid desc  
    20.     </select>  
    21.   
    22.   
    23.     <insert id="insertAccount" parameterClass="account">  
    24.         insert into  
    25.         user_account(username,password,groupname)  
    26.         values(#username#,#password#,#groupname#)  
    27.     </insert>  
    28. </sqlMap>  

    第五步:创建我们iBATIS的sql-map-config.xml
    创建文件sql-map-config.xml,放入类路径的ibatis文件中
    [html]  view plain copy
    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.     <settings   
    12.         useStatementNamespaces="true"   
    13.         />  
    14.       
    15.     <sqlMap resource="ibatis/Account.xml" />  
    16.       
    17. </sqlMapConfig>  

    第六步:继续配置Spring配置文件 -- 从Spring中创建SqlMapClient
    创建文件beans.xml放入类路径下的META-INF/spring中
    [html]  view plain copy
    1. <?xml version="1.0" encoding="UTF-8"?>  
    2. <beans xmlns="http://www.springframework.org/schema/beans"  
    3.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"  
    4.     xmlns:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop"  
    5.     xmlns:util="http://www.springframework.org/schema/util"  
    6.     xsi:schemaLocation="http://www.springframework.org/schema/beans  
    7.         http://www.springframework.org/schema/beans/spring-beans-3.0.xsd  
    8.         http://www.springframework.org/schema/context  
    9.         http://www.springframework.org/schema/context/spring-context-3.0.xsd  
    10.         http://www.springframework.org/schema/aop  
    11.         http://www.springframework.org/schema/aop/spring-aop-2.5.xsd  
    12.         http://www.springframework.org/schema/util  
    13.         http://www.springframework.org/schema/util/spring-util-3.0.xsd">  
    14.     <aop:aspectj-autoproxy />  
    15.     <context:component-scan base-package="com.partner4java" />  
    16.       
    17.     <import resource="classpath:META-INF/spring/datasource-c3p0.xml" />  
    18.       
    19.     <!-- SqlMapClientFactoryBean是个Spring工厂Bean,用于生成SqlMapClient。  
    20.         iBATIS API的核心是SqlMapClient接口。  
    21.         SqlMapClient大致相当于Hibernate的Session或者JPA的EntityManager,用于执行全部的数据访问操作。 -->  
    22.     <bean id="sqlMapClient" class="org.springframework.orm.ibatis.SqlMapClientFactoryBean">  
    23.         <property name="dataSource" ref="dataSource"/>  
    24.         <property name="configLocation" value="classpath:ibatis/sql-map-config.xml"/>  
    25.     </bean>  
    26.       
    27.     <!-- SqlMapClientTemplate包裹了一个SqlMapClient来透明的打开和关闭会话,好捕获抛出的SQLException。 -->  
    28.     <bean id="sqlMapClientTemplate" class="org.springframework.orm.ibatis.SqlMapClientTemplate">  
    29.         <property name="sqlMapClient" ref="sqlMapClient"/>  
    30.     </bean>  
    31.           
    32. </beans>          

    第七步:创建我们的Service
    [java]  view plain copy
    1. public interface AccountService {  
    2.     List<Account> query(String groupname);  
    3.     void add(Account account);  
    4. }  
    5.   
    6.   
    7. @Service  
    8. public class AccountServiceBean implements AccountService {  
    9.     @Autowired  
    10.     private SqlMapClientTemplate sqlMapClientTemplate;  
    11.     public void setSqlMapClientTemplate(  
    12.             SqlMapClientTemplate sqlMapClientTemplate) {  
    13.         this.sqlMapClientTemplate = sqlMapClientTemplate;  
    14.     }  
    15.   
    16.   
    17.     public List<Account> query(String groupname) {  
    18.         return sqlMapClientTemplate.queryForList("Account.queryAccount",  
    19.                 groupname);  
    20.     }  
    21.   
    22.   
    23.     public void add(Account account) {  
    24.         sqlMapClientTemplate.insert("Account.insertAccount", account);  
    25.     }  
    26.   
    27.   
    28. }  

    最后一步:测试
    [java]  view plain copy
    1. public class AccountServiceBeanTest {  
    2.     ApplicationContext applicationContext;  
    3.     private AccountService accountService;  
    4.     @Before  
    5.     public void setUp() throws Exception {  
    6.         applicationContext = new ClassPathXmlApplicationContext(  
    7.                 "META-INF/spring/beans.xml");  
    8.         accountService = applicationContext.getBean("accountServiceBean", AccountService.class);  
    9.     }  
    10.   
    11.   
    12.     @Test  
    13.     public void testQuery() {  
    14.         System.out.println(accountService.query(null));  
    15.     }  
    16.   
    17.   
    18. }  
  • 1
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值