1.传统方法的弊端

还记得在Mybatis入门&配置文件&映射文件这篇文章中,我们写的Mybatis访问数据库执行sql语句的代码。是通过如下代码

// 读取Message.xml中的sql语句 
messages = sqlSession.selectList("Message.getList", message);
sqlSession.commit();

首先Message对应的是Message.xml文件中的namespace,getList是我们sql语句的id,通过Message.getList我们就可以访问该映射文件中的sql语句。这样做有什么坏处呢?有以下四个缺点

  1. 为了确保命名空间的唯一性,namespace我们一般起的都是比较长的,这样通过namespace.id取sql语句,就会存在出错的可能性,因为你可能手误啥的,关键是不管比怎么写,它是一个字符串,不会给你报错啊。真正等你运行起来的时候,一大堆代码,那时候就一脸懵逼了。
  2. selectList方法的第二个参数是Object,也就是说你可以传入任何类型,当然,正确的答案就是传入符合sql语句定义的parameterType,然而因为方法要求的是Object类型,所以你传啥都不会报错,这又埋下了隐患。
  3. selectList方法返回的一个Object类型,万一你手抖用了一个错误的类型去接它的返回值,这又是一个隐患。
  4. 最后还得sqlSession.commit(),这个也很容易忘记。

基于以上,我们就使用接口式编程,这也正是Mybatis提倡我们做的。


2.接口式编程

其实在Mybatis中,所谓接口编程,就是我们定义一个代理接口,对应相应的数据表的配置文件,比如一个Message.xml,对应数据库中的message表,Message.xml如下

<!-- 一个名字空间 -->
<mapper namespace="Message">
    <!-- 和数据库的表字段相对应 ,type表示相应的实体类--> 
    <resultMap type="com.codeliu.bean.Message" id="MessageResult"> 
        <!-- 主键 column表示数据库中的字段,property表示实体类对应的属性--> 
        <id column="id" jdbcType="INTEGER" property="id"/> 
        <result column="command" jdbcType="VARCHAR" property="command"/> 
        <result column="description" jdbcType="VARCHAR" property="description"/> 
        <result column="content" jdbcType="VARCHAR" property="content"/> 
    </resultMap> 
    <!-- 同一个命名空间下的id要唯一 --> 
    <select id="getList" resultMap="MessageResult" parameterType="com.codeliu.bean.Message"> 
        select id,command,description,content from message
        <where> 
            <if test="command != null and !&quot;&quot;.equals(command.trim())"> 
                and command = #{command} 
            </if> 
            <if test="description != null and !&quot;&quot;.equals(description.trim())"> 
                and description like '%' #{description} '%' 
            </if> 
        <where>
    </select>
</mapper>

我们定义一个接口IMessage.java,代码如下

package com.codeliu.dao;

import com.codeliu.bean.Message;
public interface IMessage {
    /** 
     * 函数名对应Message.xml中相应SQL语句的id
     * @param message 对应Message.xml中相应SQL语句的parameterType
     * @return
     */ 
    public Message getList(Message message);
}

可以看到该接口中有一个方法,方法名对应sql语句的id,参数是sql语句的parameterType,返回值是sql语句查询结果的对应的实体。

有了这个接口,我就可以改变上面那个读取数据的方式。把上面两句注释掉,换成如下的语句

IMessage imessage = sqlSession.getMapper(IMessage.class); 
// 这个parameters就是传进来的参数
messages = imessage.getList(parameters);

记得还要改映射文件Message.xml的namespace,一开始的值为Message,现在改成该接口的完整路径,也就是com.codeliu.dao.IMessage。这样就形成了一种对应关系,如果Message.xml中有多个sql语句,就可以在接口中添加对应的方法,这样就避免了上述的四个缺点。


3.原理探索

讲了上面的这么多,同志们有没有很好奇,写了个接口,定义了一个方法,改了下路径,Mybatis就知道执行这条SQL?真神奇,到底是怎么执行的呢?答案就在源码里。先说一下,就是使用动态代理的机制。关于动态代理,我下一篇文章再讲,顺带涉足一下源码。毕竟学框架,必须得看源码。


老师说,框架归根到底,底层实现还是Java语言,所以不要怕看源码,看懂了其实也就那样,还能学习它们优秀的思想,实力也会上一个层次。加油吧!

个人博客https://www.codeliu.com