iBatis开发指南

      相对于Hibernate一站式的ORM解决方案而言,iBatis之一种半自动化的ORM实现;在一定情况下,这种一站式的ORM解决方案有时候会有一定的问题出现,例如:

      1.开发规范中要求,所有业务部分的数据库操作,必须在数据库层由存储过程实现;

      2.系统数据量较大,对性能有苛刻要求,需要执行我们高度优化过的SQL语句。

      面对这样的需求,我们发现iBatis是一个很好的选择,我们面对的是纯粹的java对象,同时SQL语句由我们自己来编写。

 

一、iBatis使用介绍

      1.ibatis全局配置文件

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE sqlMapConfig PUBLIC "-//iBATIS.com//DTD SQL Map Config 2.0//EN" "http://www.iBATIS.com/dtd/sql-map-config-2.dtd">

<sqlMapConfig>
    
    <settings 
     cacheModelsEnabled="true" 
     enhancementEnabled="true"
     lazyLoadingEnabled="true"
     errorTracingEnabled="true"
     maxRequests="32" 
     maxSessions="10" 
     maxTransactions="5" 
     useStatementNamespaces="false"
     />
     
     <transactionManager type="JDBC">
         <dataSource type="SIMPLE">
             <property name="JDBC.Driver" value="com.mysql.jdbc.Driver" />
             <property name="JDBC.ConnectionURL" value="jdbc:mysql://127.0.0.1:3309/sample" />
             <property name="JDBC.Username" value="root" />
             <property name="JDBC.Password" value="root" />
             <property name="Pool.MaximumActiveConnections" value="10" />
             <property name="Pool.MaximumIdleConnections" value="5" />
             <property name="Pool.MaximumCheckoutTime" value="120000" />
             <property name="Pool.TimeToWait" value="500" />
             <property name="Pool.PingQuery" value="select 1 from sample" />
             <property name="Pool.PingEnabled" value="false" />
             <property name="Pool.PingConnectionsOlderThan" value="1" />
             <property name="Pool.PingConnectionsNotUsedFor" value="1" />
         </dataSource>
     </transactionManager>
     
     <sqlMap resource="IBatisTest/UserInfo.xml" />
     
</sqlMapConfig>

     配置说明:cacheModelsEnabled:是否启用SqlMapClient上的缓存机制,建议为true

     enhancementEnabled:是否针对POJO启动字节码增强机制以提升get/set调用效能,避免反射带来的性能开销,建议为true

     lazyLoadingEnabled:是否启用延迟加载机制,建议为true

     errorTracingEnabled:是否启用错误日志,开发期间建议为true

     maxRequests:最大并发请求数,建议为true

     maxTransactions:最大并发事务数,建议为true

     maxSessions:最大session数,即当前允许的最大并发SqlMapClient数,maxSessions数必须大于maxTransactions,小于maxRequests

     useStatementNamespaces:是否使用Statement命名空间,指映射文件中,SqlMap节点的UserInfo属性,

                                             如果设置为true,调用的时候需要写成:sqlMap.update("UserInfo.upDateUserInfo", userInfo);

     2.持久化类

package IBatisTest;

import java.io.Serializable;

public class UserInfo implements Serializable {

    /**
     * 
     */
    private static final long serialVersionUID = -4774273886584667516L;
    
    private Integer userId;
    private String userName;
    private Integer userSex;

    public UserInfo() {

    }

    public Integer getUserId() {
        return userId;
    }

    public void setUserId(Integer userId) {
        this.userId = userId;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public Integer getUserSex() {
        return userSex;
    }

    public void setUserSex(Integer userSex) {
        this.userSex = userSex;
    }

}

     3.关系-对象映射文件

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE sqlMap PUBLIC "-//iBATIS.com//DTD SQL Map 2.0//EN" "http://www.iBATIS.com/dtd/sql-map-2.dtd">
<sqlMap namespace="UserInfo">
    <typeAlias alias="UserInfo" type="IBatisTest.UserInfo" />
    
    <insert id="addUser" parameterClass="UserInfo" >
        <![CDATA[
            insert into userinfo (username,usersex) values(#userName#,#userSex#)
        ]]>
    </insert>
    
    <select id="getUserInfo" parameterClass="java.lang.String" resultClass="UserInfo" >
        <![CDATA[
            select userId,usersex from UserInfo where username = #userName#
        ]]>
    </select>
    
    <select id="getAllUser" resultClass="UserInfo" >
        <![CDATA[
            select userId,userName,usersex from UserInfo
        ]]>
    </select>
    
    <update id="upDateUserInfo" parameterClass="UserInfo">
        <![CDATA[
            update userinfo set usersex=#userSex# where username = #userName#
        ]]>
    </update>
    
    <delete id="deleteUser" parameterClass="java.lang.Integer">
        <![CDATA[
            delete from userinfo where userid=#userId#
        ]]>
    </delete>
    
</sqlMap>

  其中映射文件中的#参数#对应的名称是持久话类中的属性名,iBatis会利用反射去get/set操作;

     4.iBatis操作数据

package IBatisTest;

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

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

public class test {

    @SuppressWarnings({ "unchecked", "unchecked" })
    public static void main(String[] args) {

        String resource = "IBatisData/SqlMapConfig.xml";
        Reader reader;
        try {
            reader = Resources.getResourceAsReader(resource);
            SqlMapClient sqlMap = SqlMapClientBuilder.buildSqlMapClient(reader);
            try {
                sqlMap.startTransaction();
            } catch (SQLException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            UserInfo userInfo = new UserInfo();
            userInfo.setUserName("aaa");
            userInfo.setUserSex(111);
            // userInfo.setUserId(2);
            List<UserInfo> userResult = null;
            UserInfo user2 = null;
            try {
                sqlMap.delete("deleteUser", userInfo.getUserId());
                sqlMap.insert("addUser", userInfo);
                sqlMap.update("upDateUserInfo", userInfo);
                userResult = sqlMap.queryForList("getUserInfo",
                        userInfo.getUserName());
                user2 = (UserInfo) sqlMap.queryForObject("getUserInfo",
                        userInfo.getUserName());
                Iterator<UserInfo> it = userResult.iterator();
                while (it.hasNext()) {
                    UserInfo user = it.next();
                    System.out.println(user.getUserSex()+"-"+user2.getUserId());
                }
                
                //list分页查询
                PaginatedList list = sqlMap.queryForPaginatedList("getAllUser", 2);
                System.out.println("第一页:");
                for(int i=0;i<list.size();i++){
                    UserInfo user =(UserInfo)list.get(i);
                    System.out.println(user.getUserName());
                }
                list.nextPage();
                System.out.println("第二页:");
                for(int i=0;i<list.size();i++){
                    UserInfo user =(UserInfo)list.get(i);
                    System.out.println(user.getUserName());
                }
                
                //Map批量查询
                Map userMap = sqlMap.queryForMap("getAllUser", null, "userId");
                UserInfo userFromMap = (UserInfo) userMap.get(3);
                System.out.println(userFromMap.getUserName());
                
                sqlMap.commitTransaction();
                
            } catch (SQLException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

}

     5.缓存机制的配置,我们可以在映射文件中配置缓存机制

<typeAlias alias="UserInfo" type="IBatisTest.UserInfo" />
    
    <cacheModel id="userCache" type="LRU">
        <flushInterval hours="24"/>
        <flushOnExecute statement="upDateUserInfo" />
        <property name="size" value="1000" />
    </cacheModel>

    我们在使用缓存的时候,可以直接使用userCache

<select id="getUserInfo" parameterClass="java.lang.String" resultClass="UserInfo" cacheModel="userCache" >
        <![CDATA[
            select userId,usersex from UserInfo where username = #userName#
        ]]>
</select>

    这样我们通过对id为getUserInfo的Select Statement获取数据的时候,使用userCache进行缓存,之后程序再次执行这个Statement的时候,直接从缓存结果中取数据,无需再次执行SQL语句;flushInterval设置缓存的超时清空时间;flushOnExecute执行特定的Statement的时候将缓存清空;size缓存池中容纳的最大对象数量;

    有时候,数据库表中的字段过于晦涩,为了使代码更易于理解,我们在映射到POJO时候,采用比较易读的属性名,我们可以采用select的as对字段进行转移,例如:

<select id="getUserInfo" parameterClass="java.lang.String" resultClass="UserInfo" cacheModel="userCache" >
        <![CDATA[
            select userId,xingbie as userSex from UserInfo where username = #userName#
        ]]>
</select>

    这样,iBatis会根据转以后的字段名进行POJO映射;有时候存储过程相对而言比较封闭,我们难以通过select as进行字段名转义,此时通过使用resultMap来建立字段名和POJO中属性的映射就显得非常有效:

<resultMap id="getUserInfoMap" class="UserInfo">
        <result property="name" column="xinming" jdbcType="VARCHAR" javaType="java.lang.String" />
</resultMap>

    随后我们可以在Statement声明中对其引用:

<procedure id="getUserInfoList" resultMap="getUserInfoMap">
        {call sp_getUserInfoList()}
</procedure>

 

二、iBatis高级特性

     1.通过Statement嵌套实现关联数据的操作

     a.一对多关联

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE sqlMap PUBLIC "-//iBATIS.com//DTD SQL Map 2.0//EN" "http://www.iBATIS.com/dtd/sql-map-2.dtd">
<sqlMap namespace="UserInfo">
    <typeAlias alias="UserInfo" type="IBatisTest.UserInfo" />
    <typeAlias alias="UserAddress" type="IBatisTest.UserAddr" />
    
    <cacheModel id="userCache" type="LRU">
        <flushInterval hours="24"/>
        <flushOnExecute statement="upDateUserInfo" />
        <property name="size" value="1000" />
    </cacheModel>
  <resultMap id="getUserResult" class="UserInfo">
        <result property="userId" column="userid" />
        <result property="userName" column="username" />
        <result property="userSex" column="usersex" />
        <result property="userAddr" column="username" select="getUserAddrByName" />
    </resultMap>
    <select id="getUserInfoList" parameterClass="java.lang.String" resultMap="getUserResult">
        <![CDATA[
            select userid,username,usersex from userinfo where username = #userName#
        ]]>
    </select>
    <select id="getUserAddrByName" parameterClass="java.lang.String" resultClass="java.lang.String">
        <![CDATA[
            select useraddr from useraddress where username = #userName#
        ]]>
    </select>
</sqlMap>
List<UserInfo> userList = sqlMap.queryForList("getUserInfoList","libin");
                for(int i=0; i<userList.size();i++){
                    UserInfo user0 = userList.get(i);
                    System.out.println("-->"+user0.getUserAddr());
                }

   b.一对一关联

<resultMap id="getUserResult" class="UserInfo">
        <result property="userId" column="userid" />
        <result property="userName" column="username" />
        <result property="userSex" column="usersex" />
        <result property="userAddr" column="useraddress.useraddr" />
        <!-- <result property="userAddr" column="username" select="getUserAddrByName" />-->
    </resultMap>
<select id="getUserInfoList" parameterClass="java.lang.String" resultMap="getUserResult">
        <!--
        <![CDATA[
            select userid,username,usersex from userinfo where username = #userName#
        ]]>
        -->
        <![CDATA[
            select userinfo.userid,userinfo.username,userinfo.usersex,useraddr from userinfo,useraddress where userinfo.username = #userName# and userinfo.username = useraddress.username
        ]]>
    </select>
    <select id="getUserAddrByName" parameterClass="java.lang.String" resultClass="java.lang.String">
        <![CDATA[
            select useraddr from useraddress where username = #userName#
        ]]>
    </select>

    两种方式都可以实现多表之间的关联;

    2.延迟加载

     当我们执行List<UserInfo> userList = sqlMap.queryForList("getUserInfoList","libin");时候,实际上iBatis只向数据库发送了一条:select userid,username,usersex from userinfo where username = #userName#语句,用于查询addr的SQL,只有在我们真正访问useraddress对象的时候才执行,这就是延迟加载,Lazy Loading.

    3.动态映射

<select id="getUserInfo" parameterClass="UserInfo" resultClass="UserInfo" cacheModel="userCache" >
        <![CDATA[
            select userId,usersex from UserInfo where username = #userName#
        ]]>
        <dynamic>
            <isNotEmpty prepend="AND" property="userId">
                <![CDATA[
                userid = #userId#
                ]]>
            </isNotEmpty>
        </dynamic>
</select>

  该Statement会判断POJO的userId属性是否为空来决定是否添加SQL: AND userid=userid,根据逻辑需要,isNotEmpty 还可以进行嵌套;

      如果<dynamic>下有多个<isNotEmpty>,where子句中第一个子句需不需要and,iBatis会自动进行判断忽略,其他判定节点如下:

转载于:https://www.cnblogs.com/NicholasLee/archive/2012/07/24/2606621.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值