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语句。这样做有什么坏处呢?有以下四个缺点
- 为了确保命名空间的唯一性,namespace我们一般起的都是比较长的,这样通过namespace.id取sql语句,就会存在出错的可能性,因为你可能手误啥的,关键是不管比怎么写,它是一个字符串,不会给你报错啊。真正等你运行起来的时候,一大堆代码,那时候就一脸懵逼了。
- selectList方法的第二个参数是Object,也就是说你可以传入任何类型,当然,正确的答案就是传入符合sql语句定义的parameterType,然而因为方法要求的是Object类型,所以你传啥都不会报错,这又埋下了隐患。
- selectList方法返回的一个Object类型,万一你手抖用了一个错误的类型去接它的返回值,这又是一个隐患。
- 最后还得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 !"".equals(command.trim())">
and command = #{command}
</if>
<if test="description != null and !"".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语言,所以不要怕看源码,看懂了其实也就那样,还能学习它们优秀的思想,实力也会上一个层次。加油吧!