今天就看一下MyBatis的查询的源码,上一篇写了解析sql语句,其实就是将sql语句封装成一个个的SqlNode,然后将SqlNode封装成SqlSource,最后将所有信息保存到一盒MappedStatement对象中。MyBatis执行我们的sql语句是使用了JDK动态代理的模式的。
首先看下入口,是在org.apache.ibatis.binding.MapperProxy类中的invoke方法
跟进这个mapperMethod.execute(this.sqlSession, args)方法
已经可以看到我们想看到的了,有INSERT UPDATE DELETE SELECT,今天先看下SELECT方法。
查询这里有很多的条件判断,主要是根据你自己写的方法的返回值来决定的,比如你返回一个Map,或者返回一个集合等。
首先看下最简单的,查一条数据的,也就是 else 分区,这里有二个方法
第一行代码就是解析我们方法的参数的。比如我们现在执行的方法是
People selectById(@Params("id")int id,@Params("name")String name)
这里根据id和name查询一条记录,跟进这个方法到达 ParamNameResolver 类中,它有一个构造函数。
如果我们参数有@param注解,那么解析出来的结构就是{"id":1,"name":'123'},如果没有@Param注解那么解析出来的就是{arg0:1,arg1:'123'},因为id的序号是0嘛,所以就是arg0,name的序号是1,所以就是arg1。
接下来看下sqlSession.selectOne()方法,在DefaultSqlSession类中。
图中这个异常估计大家都碰过,跟进这个this.selectList方法
首先就是获取相关的MappedStatement对象,因为之前解析好的sql语句片段都放在了这个对象中,那么根据什么获取呢,因为在解析配置文件的时候就知道了我们写的查询方法跟Mapper*.xml是绑定了的,所以就可以根据 namespace的id + 方法名的id去获取到这个对象,这也是为什么说namespace的id要唯一,不然你就获取不到这个对象了。继续跟进这个query()方法
进到BaseExecutor这个类中,这是一个执行器哈,MyBatis所有的sql的执行都是经过执行器执行的
1:获取BoundSql对象
2:创建缓存(这里暂时不分析,后面会讲)
3:继续执行quey()方法
首先看下这个BoundSql对象是什么,跟进方法进入到DynamicSqlSource类的getBoundSql()方法,我们先看下最后得到的boundSql
是什么样的。执行的方法是
方法:
Peopel selectOne(@Param("name")String name, @Param("id")int id);
配置文件:
<select id='selectOne'>
select * from test where 1 = 1 and id = ${id} and name = #{name}
</select>
在整个getBoundSql中有涉及到完整的sql拼接,还有 ${} 和 #{} 的解析。今天快下班了,明天继续补上,不好意思了