南京北大青鸟

全国咨询电话:15195455103

三分钟了解北大青鸟
当前位置:南京北大青鸟 > 学习园地 > 编程技巧

ibatis技术文档

来源:南京北大青鸟张府园校区      作者:IT教育      发布时间:2012-07-31 17:42:30

ibatis一词来源于“internet”和“abatis”的组合,是一个由Clinton Begin在2001年发起的开放源代码项目。初侧重于密码软件的开发,现在是一个基于Java的持久层框架。 将“Internet”中象征

ibatis介绍
ibatis简介:
 ibatis一词来源于“internet”和“abatis”的组合,是一个由Clinton Begin在2001年发起的开放源代码项目。初侧重于密码软件的开发,现在是一个基于Java的持久层框架。
 将“Internet”中象征性的“i”和abatis中的“batis”组合所以暗示了抵御Internet的意思。
 相对Hibernate和Apache OJB等“一站式”ORM解决方案而言,ibatis 是一种“半 自动化”的ORM实现。
 ibatis需要手写sql语句,也可以生成一部分,Hibernate则基本上可以自动生成,偶尔会写一些Hql。同样的需求, ibatis的工作量比Hibernate要大很多。类似的,如果涉及到数据库字段的修改,Hibernate修改的地方很少,而ibatis要把那些sql mapping的地方一一修改。
 可维护性方面,ibatis更好一些。因为 iBatis 的 sql 都保存到单独的文件中。而 Hibernate 在有些情况下可能会在 java 代码中保sql/hql。
 如果你开发一个新系统,希望完全控制对象模型,进行数据库设计,那么Hibernate是一个好的选择;如果你工作在一个很古老的数据库系统上,数据库设计非常糟糕,你又没有权利去改变数据库设计,那么iBATIS更合适一些。
 因为ibatis是以SQL的方式开发,所以ibatis自身是不能动态生成表的,当然可以把SQL预先写入xml中,但是这种方式在开发中使用率并不高,并且以后不断的建表会比较繁琐,所以通常情况下,我们需要首先创建表,然后再使用ibatis来操作数据,在这方面,就没有hibernate建表那么容易。
 
ibatis简单入门
ibatis快速开发:
 创建一个java项目,然后导入驱动包到lib文件夹下面,我们需要的驱动包有ibatis-2.3.4.726.jar和classes12.jar,然后添加一个SqlMapConfig.xml到src下面,在此xml中写入以下内容:
<?xml version="1.0" encoding="UTF-8" ?>

<!DOCTYPE sqlMapConfig     
    PUBLIC "-//ibatis.apache.org//DTD SQL Map Config 2.0//EN"     
    "http://ibatis.apache.org/dtd/sql-map-config-2.dtd">

<sqlMapConfig>

  <transactionManager type="JDBC" commitRequired="false">
    <dataSource type="SIMPLE">
      <property name="JDBC.Driver" value="oracle.jdbc.driver.OracleDriver"/>
      <property name="JDBC.ConnectionURL" value="jdbc:oracle:thin:@localhost:1521:ORAC"/>
      <property name="JDBC.Username" value="test"/>
      <property name="JDBC.Password" value="test"/>
    </dataSource>
  </transactionManager>

  <sqlMap resource="com/cn/thinkmore/bean/BuMen_SqlMap.xml"/>

</sqlMapConfig>

然后创建一个pojo,对应数据库中的一个表,例如:
package com.cn.thinkmore.bean;

public class BuMen {
 private String bid;

 private String bumenname;
 
 private String bumencode;

 public BuMen(){}
 
 public String getBumencode() {
  return bumencode;
 }

 public void setBumencode(String bumencode) {
  this.bumencode = bumencode;
 }

 public String getBid() {
  return bid;
 }

 public void setBid(String bid) {
  this.bid = bid;
 }

 public String getBumenname() {
  return bumenname;
 }

 public void setBumenname(String bumenname) {
  this.bumenname = bumenname;
 }

}
接着创建此pojo的映射xml文件,名字自定义,尽量pojo类名_SqlMap命名,我在这里的创建的POJO类名叫BuMen,所以我创建此xml文件叫BuMen_SqlMap.xml
<?xml version="1.0" encoding="UTF-8" ?>

<!DOCTYPE sqlMap     
    PUBLIC "-//ibatis.apache.org//DTD SQL Map 2.0//EN"     
    "http://ibatis.apache.org/dtd/sql-map-2.dtd">

<sqlMap>

  <select id="selectAll" resultClass="com.cn.thinkmore.bean.BuMen">
      select bid,bumenname,bumencode from BuMen
  </select>

</sqlMap>

后,我们来创建一个带有main方法的测试类:
package com.cn.thinkmore.bean;

import java.io.IOException;
import java.io.Reader;
import java.sql.SQLException;
import java.util.List;

import com.ibatis.common.resources.Resources;
import com.ibatis.sqlmap.client.SqlMapClient;
import com.ibatis.sqlmap.client.SqlMapClientBuilder;

public class TestConsole {
 
   private static SqlMapClient sqlMapClient;
 
 static {
     try {
       Reader reader = Resources.getResourceAsReader("SqlMapConfig.xml");
       sqlMapClient = SqlMapClientBuilder.buildSqlMapClient(reader);
       reader.close();
     } catch (IOException e) {
       // Fail fast.
       throw new RuntimeException("Something bad happened while building the SqlMapClient instance." + e, e);
     }
   }
 public static void main(String[] args) {
  try {
   List list = sqlMapClient.queryForList("selectAll");
   System.out.println(list);
   for(Object obj:list){
    BuMen bm = (BuMen)obj;
    System.out.println("bid="+bm.getBid()+"   bumenname="+bm.getBumenname()+"  bumencode="+bm.getBumencode());
   }
  }catch (SQLException e) {
   e.printStackTrace();
  }
 }
}
后运行成功,这样我们就快速搭配起来了ibatis的环境了。
ibatis核心技术
ibatis配置文件---sqlMapConfig.xml:
 下面,我们来详细介绍sqlMapConfig中的常用标签:
 
<sqlMapConfig>
  配置文件的父标签,所有标签必须写在此标签内部。

<properties/>       
 引用属性文件,用于引用标准的propertis属性文件。
 在属性文件中定义的属性,可以作为变量在配置文件及其包含的所有映射文件中引用,例如:如果在属性文件中包含如下属性:
 url=jdbc:oracle:thin:@localhost:1521:ORAC
 那么就可以在xml文件中,这样调用:
 <property name=" JDBC.ConnectionURL" value="${url}"/>
               
<settings/>         
 设置属性,用于配置和优化SqlMap实例的各种属性,此标签本身及其所有的属性都是可选的。下面是它的内部属性介绍:
 maxRequests:同时执行SQL语句的大线程数。大于这个值的时候,后面的线程将被阻塞,直到有线程执行完成,不同的数据库有不同的限制值,但是任何数据库通常应该把此属性值设置为maxTransactions的10倍,并且总是大于maxSessions和maxTransactions,减少此值可能会提高性能(默认值 512)
 maxSessions:同一时间内活动的大Session数,一个Session可以是代码请求的显式Session,也可以是当线程使用SqlMapClient实例(执行一条语句)自动获得的Session,它应该总是大于或者等于maxTransactions
并且小于maxRequests,减小这个参数值可能会减少内存使用(默认值 128)
 maxTransactions:同时进入SqlMapClient.startTransaction()的大线程数,大于这个值的线程将阻塞直到另一个线程退出。不同的数据库有不同的限制值,但任何数据库都有这些限制,这个参数值应该总是小于或等于maxSessions,并总是远远小于maxRequests,减小这个参数值可能会提高性能(默认值 32)
 cacheModelsEnabled:全局性的启用或禁用SqlMapClient的所有缓存Model,在调试程序时使用(默认值 true)
 lazyLoadingEnabled:全局性的启用或禁用SqlMapClient的所有延迟加载,在调试程序时使用(默认值 true)
 useStatementNamespaces:如果启用本属性,则必须使用全限定名来引用执行命令,例如:sqlMapClient.queryForObject("映射文件名.方法名");
(默认值 false)      
        
<transactionManager/>  
 定义事务管理器,包含一个唯一的属性type,用以指定使用的事务管理器类型。有三种不同的选择:JDBC,JTA,EXTERNAL
 JDBC:让jdbc来管理事务(常用)
 JTA:使用JTA全局事务
 EXTERNAL:可以让开发人员来管理事务
        
<dataSource/>     
 定义数据源,type="SIMPLE"定义一个基本的实现,基于ibatis的SimpleDataSource连接池实现,其别名为SIMPLE
  
<property/>      
 设置数据源参数
 JDBC.Driver           JDBC驱动程序类名
 JDBC.ConnectionURL    数据库URL
 JDBC.Username         数据库用户名
 JDBC.Password         数据库密码
 JDBC.DefaultAutoCommit 连接池中所有连接默认的自动提交模式(默认为true)
 Pool.MaximumActiveConnections 数据库连接池可维持的大容量 默认值为10
 Pool.MaximumIdleConnections  数据库连接池中允许的挂起连接数,默认值为5
 
<sqlMap/>       
 引用映射文件

POJO映射文件---SqlMap.xml:

<sqlMap namespace="BuMen">
  此配置文件的父标签,所有标签都需要配置在此标签内部,它可以设定一个命名空间,但是通常没有作用。

<typeAlias alias="BuMen" type="com.cn.thinkmore.bean.BuMen"/>
 为POJO设置一个别名,为了在使用SQL标签的时候引用,例如:
 <select id="selectOne" resultClass="BuMen">
 type属性是指定POJO的包名+类名,alias属性是给此POJO定义一个别名,为以后调用

<resultMap id="BuMenResult" class="BuMen">
    <result property="bid" javaType="java.lang.String" column="bid" jdbcType="varchar2" nullValue="null"/>
    <result property="bumenname" column="bumenname"/>
    <result property="bumencode" column="bumencode"/>
</resultMap>
 设置结果集映射,优先选用resultClass而不是resultMap,此标签大多时候用于存储过程的处理
 id:引用的值
      class:映射的POJO
      result标签是指定每一个属性
      property:指定关联的属性名
      javaType:指定属性的类型
      column:指定此属性关联的字段名
      jdbcType:指定字段的类型
      nullValue:当此属性没有取到值的时候,指定的默认值
 通常情况下,只需要设置property和column属性。

 下面介绍在ibatis中怎么操作数据库的增删改查,对应的标签分别是insert, delete,update,select,在这四个标签中,都有id,resultClass,parameterClass常用属性:

 id:指定要调用的名字
 parameterClass:指定传入参数的类型,例如:parameterClass="com.cn.thinkmore.bean.BuMen",也可以设定为基本类型
parameterMap:指定传入参数的类型,(很少使用)
resultClass:指定返回的类型,例如:
 resultClass="com.cn.thinkmore.bean.BuMen",也可以设定为基本类型
resultMap:指定返回的类型,(很少使用)

  注意:为了避免特殊符号与XML的标签冲突,所以有时候需要使用
<![CDATA[select * from BuMen where bid<#bid#]]>的方式来编写SQL

<select id="selectAll" resultClass="com.cn.thinkmore.bean.BuMen">
      select bid,bumenname,bumencode from BuMen
</select>
 定义一个SQL的插入语句,ibatis会自动根据select语句中的字段名,调用对应POJO 的set方法设定属性值,如上例中,ibatis会调用setBid,setBumenname,setBumencode 方法将Select语句返回的数据,装载到相应的POJO实例属性中。
 
<insert id="insertObj" parameterClass="com.cn.thinkmore.bean.BuMen">
    insert into BuMen(bid,bumenname,bumencode) values (#bid#,#bumenname#,#bumencode#)
</insert>
 定义一个SQL的插入语句,ibatis会自动根据select语句中的字段名,调用对应POJO 的get方法设定属性值,如上例中,ibatis会调用getBid,getBumenname,getBumencode 方法将POJO实例属性中的值插入了SQL语句中。

<delete id="deleteObj" parameterClass="int">
   delete from BuMen where bid=#bid#
</delete>
  定义一个SQL的删除语句,parameterClass属性定义传入的类型为Integer类型,它会自动添加到#bid#位置,现在的#bid#不会再调用set或者get,ibatis会自动把它当做填充符使用。

<update id="updateObj" parameterClass="bumen">
   update bumen set bid=#bid#,bumenname=#bumenname#,bumencode=#bumencode# where bumencode=#bumencode#
</update>
 定义一个SQL的更新语句。
 
使用SqlMapClient操作
 SqlMapClient的开发:
 每一个Dao或者Service都会有一个SqlMapClient的实例,通常情况,我们并不希望外部能访问此实例对象,所以我们需要这样做:
    private static SqlMapClient sqlMapper;
 为了让程序在开始的时候就可以操作数据库,所以,我们还需要一个静态方法来自动创建这个实例:
 static {
     try {
       Reader reader = Resources.getResourceAsReader("SqlMapConfig.xml");
       sqlmapClient = SqlMapClientBuilder.buildSqlMapClient(reader);
       reader.close();
     } catch (IOException e) {
       // Fail fast.
       throw new RuntimeException("Something bad happened while building the SqlMapClient instance." + e, e);
     }
    }
 这样做了以后,我们就可以创建我们想操作数据库的方法了。
 我们在第二章里面已经学习怎样快速搭建ibatis并且把它使用起来了,现在来说说,开发中,有哪些方法可以让我们操作,这些方法都需要SqlMapClient的实例来调用。
 
 1. sqlmapClient.queryForList(String id)  基于一个id指定的sql来执行查询,返回一个List
 2. sqlmapClient.queryForList(String id,Object param) 基于一个id和一个字符串参数来执行查询,返回一个List
 3. sqlmapClient.queryForList(String id,Object pojo) 基于一个id和一个pojo参数来执行查询,返回一个List
 4. sqlmapClient.queryForList(String id,Object map) 基于一个id和一个map参数来执行查询(适合于多参查询的时候使用),返回一个List
 5. sqlmapClient.queryForObject(String id) 基于一个id来执行查询,返回一个Object,此方法也有4种常用方式,用法和queryForList一样,只是返回值只有一个。
 6. sqlmapClient.update(String id) 基于一个id来执行更新,返回一个Integer值决定执行了多少条记录,此方法也有4种常用方式,和queryForList类似,只是返回值是执行的结果个数
 7. sqlmapClient.insert(String id) 和update类似
 8. sqlmapClient.delete(String id) 和update类似
 
事务管理
 SqlMapClient中的事务:
sqlMapClient.startTransaction();  
 开始事务
sqlMapClient.commitTransaction();
    提交事务
sqlMapClient.endTransaction();   
   结束事务,操作失败的时候,整个事务就会在endTransaction时回滚。
 新版的ibatis中,不再有rollbackTransaction方法,只能选择endTransaction代替。
 如果代码没有显式的调用SqlMapClient.startTransaction()方法,则ibatis会将当前的数据库操作视为自动提交模式(AutoCommit=true),不过,值得注意的是,这里的所谓“自动判定”,实际上ibatis并没有去检查当前是否已经有事务开启。
    实际上,在执行update语句时,sqlMap会检查当前的Session是否已经关联了某个
数据库连接,如果没有,则取一个数据库连接,将其AutoCommit属性设为true,然后
执行update 操作,执行完之后又将这个连接释放。这样,上面两次update 操作实际上
先后获取了两个数据库连接,而不是我们通常所认为的两次update 操作都基于同一个
JDBC Connection。这点在开发时需特别注意。
 对于多条SQL 组合而成的一个JDBC 事务操作而言,必须使用startTransaction、commit和endTransaction操作以实现整体事务的原子性。
 注意!事务不能嵌套。在调用commit或end方法之前,从同一线程多次调用startTransaction将引起抛出例外。换句话说,对于每个SqlMap实例,每个线程多只能打开一个事务。
 
 
深入SqlMap.xml中的SQL开发
 增删改查4种SQL的深入化开发:

<select id="selectLike"  parameterClass="java.lang.String" resultClass="bumen">
    select * from BuMen where bumencode like '%$bumencode$%'
</select>
当我们需要使用模糊查询的时候,通配符需要特殊处理,否则无法查询到想要的数据


<select id="selectUser"  parameterClass="bumen" resultClass="int">
    select count(*) from BuMen where bid=#bid# and bumenname=#bumenname#
</select>
 我们可以使用聚集函数来查询,返回类型定义为int类型,也就是java.lang.Integer类型,这里我们传入的参数是一个POJO类型,ibatis会自动get需要的属性值,不用的属性值不会get出来,这样做虽然可以实现查询,但是看来有点浪费资源。
 
 
<resultMap id="BuMenResult" class="BuMen">
    <result property="bid" javaType="java.lang.String" column="bid" jdbcType="varchar2" nullValue="null"/>
    <result property="bumenname" column="bumenname"/>
    <result property="bumencode" column="bumencode"/>
</resultMap>
<select id="selectUser"  parameterClass="bumen" resultMap="BuMenResult">
    select count(*) from BuMen where bid=#bid# and bumenname=#bumenname#
</select>
 和上面的查询是一样的效果,只是返回的方式有所改变,我们这次选用了resultMap来返回,这样做的好处是可以让其他开发人员来看懂POJO和数据库中表的对应关系。
 
 
<select id="selectAll2" parameterClass="int" resultClass="bumen">
      <![CDATA[select bid as id,bumenname as name,bumencode as code from BuMen where bid<#bid#]]>
  </select>
 数据库表中的字段名和POJO中的属性名不相同的时候,我们希望字段映射到POJO时,我们可以通过Select的as 字句对字段名进行转义,这样就会调用POJO的setId,setName,SetCode方法装载数据。并且小于符号是xml中的关键字,使用会报错,所以,我们还需要<![CDATA[……]]>的方式来编写SQL语句。
 

<update id="updateUser" parameterClass="java.util.Map">
 update bumen
 set
 bumenname=#bumenname#,
 bumencode=#bumencode#
 where bid = #bid#
  </update>
  这里传入的参数就是一个Map对象,ibatis将以key "bid"、"bumenname"、"bumencode"从中提取对应的参数值,
  此方式大部分时候用于嵌套查询,或者多表查询,把要查询的条件以Map拼接。
  此方式还可以用于任意的增删改查SQL中,例如,我们要查询一个用户的名字和密码是否存在的时候。


<select id="getUsers" parameterClass="bumen" resultClass="bumen">
   select bid,bumenname,bumencode from bumen
   <dynamic prepend="where">
    <isNotEmpty prepend="and" property="bumenname">
   (bumenname=#bumenname#)
       </isNotEmpty>
    <isNotEmpty prepend="and" property="bumencode">
   (bumencode=#bumencode#)
    </isNotEmpty>
   </dynamic>
   </select>
 在很多时候,可能我们需要一些变化的sql语句,比如说,当用户输入几个关键字查询的时候,我们需要判断用户到底输入了几个关键字,然后通过if-else的方式,组建不同的SQL语句来操作数据库,但是这样做的话,会产生大量的代码或者配置文件内容,但是我们在使用ibatis的时候,可以避免这个问题,我们通过dynamic节点,定义了一个动态的where子句。此where子句中将可能包含两个针对bumenname和bumencode 字段的判断条件。而这两个字段是否加入查询取决于用户所提供的查询条件(字段是否为空[isNotEmpty])。
 由于ibatis会自动判定是否需要追加prepend前缀,这里(bumenname=#bumenname#)是where 子句中的第一个条件子句,无需and前缀,所以自动省略。
 当用户没有传入参数的时候,我们可以让ibatis使用全表查询,也就是上面配置中的select bid,bumenname,bumencode from bumen语句,如果用户传入了一个参数查询的时候,我们可以让ibatis基于一个条件查询,也就是上面配置中的
select bid,bumenname,bumencode from bumen where bumenname=#username#语句,如果用户传入了两个参数查询的时候,我们可以让ibatis基于两个条件查询,也就是上面配置中的
select bid,bumenname,bumencode from bumen where bumenname=#username# and bumencode=#bumencode#语句,通过这样的方式,我们就可以灵活的操作用户的查询规则,而不必要去增加太多的代码和配置内容,下面还有几种判定标签可以使用。
<isPropertyAvailable> 参数类中是否提供了此属性
<isNotPropertyAvailable> 与<isPropertyAvailable>相反
<isNull> 属性值是否为NULL
<isNotNull> 与<isNull>相反
<isNotEmpty> 属性值是否为空。
<isEmpty> 与<isNotEmpty>相反


二元判断(使用方式和dynamic节点一样,只是加入了一个属性compareValue,它可以指定一个比较值):
例如:
<isEqual prepend="AND" property="bid" compareValue="18">
            (bid=#bid#)
</isEqual>
上面的作用是如果bid属性等于18(compareValue),则在SQL中加入(bid=#bid#)条件。
同样,二元判断也有及各种判断标签供我们选择。
<isEqual> 相等。
<isNotEqual> 不等。
<isGreaterThan> 大于
<isGreaterEqual> 大于等于
<isLessThan> 小于
<isLessEqual> 小于等于


分享到:
近期文章

抢试听名额

名额仅剩66名

教育改变生活

WE CHANGE LIVES