mybatis是一个十分优秀和灵活的持久层框架,前身是ibatis,在此只对mybatis做讲解。

一:在实际的应用中,使用配置文件的方式使我们最常用的,所以这里以配置文件的方式讲解。

mybatis的主配置文件(Configuration.xml)格式如下:

<?xml version="1.0" encoding="UTF-8" ?>              
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"              
"http://mybatis.org/dtd/mybatis-3-config.dtd">              
<configuration>              
    <properties/>              
    <!--定义mybatis在运行时的行为方式 -->              
    <settings>  
        <setting name="cacheEnabled" value="true"/>              
        <setting name="lazyLoadingEnabled" value="true"/>              
        <setting name="multipleResultSetsEnabled" value="true"/>              
        <setting name="useColumnLabel" value="true"/>              
        <setting name="useGeneratedKeys" value="false"/>              
        <setting name="enhancementEnabled" value="false"/>              
        <setting name="defaultExecutorType" value="SIMPLE"/>              
        <setting name="defaultStatementTimeout" value="25000"/>              
    </settings>              
    <!--类型别名,即为java类型命名一个短的名字,然后使用该名字。框架已经定义了一些类型—>              
    <typeAliases>              
        <typeAlias alias="Author" type="domain.blog.Author"/>              
        <typeAlias alias="Blog" type="domain.blog.Blog"/>              
    </typeAliases>

    <!--类型处理器被用来将获取的值以合适的方式转换成Java类型。框架已经预定义了很多-->              
    <typeHandlers/>

    <objectFactory/>              
    <plugins/>              
    <environments default="development">              
        <environment id="development">              
            <!—JDBC和MANAGED(它会让容器来管理事务的整个生命周期(比如Spring或JEE应用服务器的上下文))-->              
            <transactionManager type="JDBC"/>              
            <!—              
                UNPOOLED(不使用连接池),              
                POOLED(使用连接池),              
                JNDI(使用JNDI接口获取数据源)。              
                不同的选项要配置的属性属性也会不一样,但它们都是提供给SqlSessionFactory所使用。              
                要注意的是,这里的连接池配置是mybatis提供给我们。               
            -->              
            <dataSource type="POOLED">              
                <property name="driver" value="${driver}"/>              
                <property name="url" value="${url}"/>              
                <property name="username" value="${username}"/>              
                <property name="password" value="${password}"/>              
            </dataSource>              
        </environment>              
    </environments>              
    <!--sql配置文件-->              
    <mappers>              
        <mapper resource="org/mybatis/example/BlogMapper.xml"/> 
    </mappers>              
</configuration>

假如定义了一个接口如下:

package org.mybatis.example;            
public interface BlogMapper{            
      List getAllMsg() ;            
      BlogModel getMsgById(Integer id) ;            
}

接着看看mapper配置文件(路径:org/mybatis/example):

<?xml version="1.0" encoding="UTF-8" ?>              
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"              
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">              
<mapper namespace="org.mybatis.example.BlogMapper">

    <resultMap type="com.mybatis.exaple.model.BlogModel" id="blogResulMap">              
        <id     property="id"         column="ID"       javaType="java.lang.String"      jdbcType="VARCHAR"/>              
        <result property="title"     column="TITLE"       javaType="java.lang.Integer"  jdbcType="NUMERIC"/>              
        <result property="content"     column="CONTENT"  javaType="java.util.Date"      jdbcType="TIMESTAMP"/>              
    </resultMap              
    <parameterMap type="com.mybatis.exaple.model.BlogModel" id="blogParametermMap">              
        <parameter property="id"         javaType="java.lang.String"   jdbcType="VARCHAR"/>              
        <parameter property="title"     javaType="java.lang.Integer"  jdbcType="NUMERIC"/>              
        <parameter property="content"     javaType="java.util.Date"        jdbcType="TIMESTAMP"/>              
    </parameterMap>              
    <select id="getAllMsg" resultType="map">              
        <![CDATA[              
             SELECT * FROM BLOG              
        ]]>              
    </select>              
    <select id="getMsgById" parameterType="int" resultMap="blogResulMap">              
        <![CDATA[              
             SELECT * FROM BLOG WHERE ID = #{id}              
        ]]>              
    </select>              
</mapper>

二:那如何在应用中启动和使用mybatis呢,操作步骤和解释如下:

1,使用SqlSessionFactoryBuilder来加载配置文件并生成SqlSessionFactory对象。SqlSessionFactory对象在整个应用中应该是单例存在的,并且除非引用被关掉了,否则将一直存在。SqlSessionFactory和数据库实例的关系是一对一。

String resource = "org/mybatis/example/Configuration.xml";            
Reader reader = Resources.getResourceAsReader(resource);              
SqlSessionFactory sqlSessionFactory              
                  = new SqlSessionFactoryBuilder().build(reader);

2,从SqlSessionFactory中获取SqlSession实例。每个线程的每次数据库操作都应该有自己的一个SqlSession,意思说该实例不应该是类的成员属性,而应该是方法的局部变量。

SqlSession session = sqlSessionFactory.openSession();

       3,使用session操作数据库(注意,这是mapper文件中已经有id为getAllmsg的sql)

try {              
    BlogMapper mapper = session.getMapper(BlogMapper.class);

   List result = mapper.getAllMsg() ;              
    // do other working              
} finally {              
    session.close();              
}

或者

BlogModel model = (BlogModel)session.selectList("org.mybatis.example.BlogMapper.getMsgById",123) ; //namespace+operatorId

注意以下两个符号的使用:

1,#{}(ibatis为:##):MyBatis创建预处理语句属性并以它为背景修改或转义字符串从

                     而设 置安全的值(比如?)。    
                     常用作查询条件的值,例如:where name=#{value}。      
                     该参数可以指定一个确切的数据类型,例如:

                    #{property,javaType=int,jdbcType=NUMERIC}.      
                     javaType通常可以从参数对象中来确定,除非对象是一个HashMap。      
                     那么javaType应该被确定来保证使用正确类型处理器。      
                     注意:如果null被当作值来传递,对于所有可能为空的列,

                    JDBC Type是需要的.      
                     为了以后自定义类型处理器,你可以指定一个确定的类型

                      处理器类(或别名),比如:      
                    #{age,javaType=int,jdbcType=NUMERIC,typeHandler=MyTypeHandler}      
                    尽管它看起来繁琐,但是实际上是你很少设置它们其中之一。      
                    对于数值类型,对于决定有多少数字是相关的,有一个数值范围。      
                    #{height,javaType=double,jdbcType=NUMERIC,numericScale=2}      
2,${}(ibatis为:$$): MyBatis不会修改或转义字符串,将会直接在SQL语句中插入

                     一个不改变的字符串,常用于拼凑sql的实体部分,

                      例如:select * from ${tableName}

三:接下来对sql配置映射文件做更深入的说明:

1,select元素

<select            
        id=”selectPerson”    //这条语句的标识。在同一命名空间只能有一个。              
        parameterType=”int” //传入该语句查询参数的数据类型              
        parameterMap=”deprecated”    //引用外部parameterMap.已经被废弃的方法.              
        resultType=”hashmap”    //返回的期望类型的类的完全限定名或别名。注意集合情形,那应该是集合可以包含的类型,而不能是集合本身.              
        resultMap=”personResultMap”    //命名引用外部的resultMap.注意:rusultType和resultMap只能使用其一。              
        flushCache="false" //将其设置为true,无论语句什么时候被调用,都会导致缓存被清空。默认值:false。              
        useCache="true" //将其设置为true,将会导致本条语句的结果被缓存。默认值:true              
        timeout="10000"              
        fetchSize="256"
        statementType="PREPARED"
        resultSetType="FORWARD_ONLY"             
        >

2,insert元素

<insert            
            id="insertAuthor"              
            parameterType="domain.blog.Author"              
            flushCache="true"              
            statementType="PREPARED"              
            keyProperty=""    //MyBatis会通过getGeneratedKeys或者通过insert语句的selectKey子元素设置它的值。默认:不设置。              
            /*              
                这会告诉MyBatis使用JDBC的getGeneratedKeys方法来取出由数据              
                (比如:像MySQL和SQL Server这样的数据库管理系统的自动递增字段)内部生成的主键。              
                默认值:false。              
            */              
            useGeneratedKeys=""              
            timeout="20000">

        例如:

1,如果你的数据库支持自动生成主键的字段

<insert id="insertAuthor" parameterType="domain.blog.Author"            
                useGeneratedKeys="true" keyProperty="id">              
                insert into Author (username,password,email,bio)              
                values (#{username},#{password},#{email},#{bio})              
</insert>

2,如果你的数据库不支持自动生成类型,或者可能JDBC驱动不支持自动生成主键时的主键生成问题。

<insert id="insertAuthor" parameterType="domain.blog.Author">            
    <selectKey keyProperty="id" resultType="int" order="BEFORE">              
        select CAST(RANDOM()*1000000 as INTEGER) a from SYSIBM.SYSDUMMY1   
    </selectKey>              
    insert into Author              
    (    id, username, password, email,bio, favourite_section)              
    values              
    (    #{id}, #{username}, #{password}, #{email}, #{bio},              
        #{favouriteSection,jdbcType=VARCHAR}              
    )              
</insert>

对selectKey元素解释:

<selectKey            
    keyProperty="id"  //执行结果应该被设置的目标属性,如上面的Author实例的id属性              
    /*              
        结果的类型。MyBatis通常可以算出来,但是写上也没有问题。              
        MyBatis允许任何简单类型用作主键的类型,包括字符串。              
    */              
    resultType="int"              
    /*              
        这可以被设置为BEFORE或AFTER.              
        BEFORE:首先选择主键,设置keyProperty然后执行插入语句.              
        AFTER:先执行插入语句,然后是selectKey元素,              
              这和如Oracle数据库相似,可以在插入语句中嵌入序列调用。              
    */              
    order="BEFORE"              
    statementType="PREPARED">

 

3,update元素

<update            
            id="insertAuthor"              
            parameterType="domain.blog.Author"              
            flushCache="true"              
            statementType="PREPARED"              
            timeout="20000">

 

4,delete元素

<delete            
            id="insertAuthor"              
            parameterType="domain.blog.Author"              
            flushCache="true"              
            statementType="PREPARED"              
            timeout="20000">

 

四:结果映射

1,通过resultMap

<resultMap id="userResultMap" type="User">            
         <id property="id" column="user_id" />              
         <result property="username" column="user_name"/>              
         <result property="password" column="hashed_password"/>              
</resultMap>

<select id=”selectUsers” parameterType="int”            
              resultMap="userResultMap”>              
            select user_id, user_name, hashed_password              
            from some_table              
            where id = #{id}              
</select>

2,通过resultType

<select id="selectUsers" parameterType="int" resultType="hashmap">          
            select id, username, hashedPassword              
            from some_table              
            where id = #{id}              
</select>

<select id="selectUsers" parameterType="int" resultType="hashmap">            
            select id as id, username as userName,              
              hashedPassword as hashedPassword              
            from some_table              
            where id = #{id}              
        </select>

注意:这两种方式得到的map的key都为全大写(ID,USERNAME,HASHEDPASSWORD)即会用列名的全大写作为key值。而下面的方式是指定属性名,在map中就等于指定key值。

<select id="selectUsers" parameterType="int" resultType="hashmap">            
            select id as "id", username as "userName",              
              hashedPassword as "hashedPassword"              
            from some_table              
            where id = #{id}              
        </select>

通过这种方式得到的key为(id,userName,hashedPassword)。

如果返回类型为一个实体对象:

<select id="selectUsers" parameterType="int" resultType="User">            
                select id, username, hashedPassword              
                from some_table              
                where id = #{id}              
</select>

这些情况下,MyBatis会在幕后自动创建一个ResultMap,基于属性名来映射列到JavaBean的属性上。那如何才能对应上呢?例如:数据库的USERNAME列可以对应上userName属性,而USER_NAME列却不能对应上userName属性。如果匹配不上,我们可以通过下面的两种方式解决。


如果列名没有精确匹配,你可以在列名上使用别名来匹配,例如:

<select id="selectUsers" parameterType="int" resultType="User">            
                select              
                   user_id as id,              
                   user_name as username,              
                   hashed_password as hashedPassword              
                from some_table              
                where id = #{id}              
</select>

其实这样时候等于是把列名user_name转换为username,然后再中新的列名去和对象的属性相匹配。而下面的这种方式是直接指定user_name列与userName属性相匹配。

<select id="selectUsers" parameterType="int" resultType="User">            
                select              
                   user_id as "id",              
                   user_name as "userName",              
                   hashed_password as "hashedPassword"              
                from some_table              
                where id = #{id}              
</select>