提示:以下是本篇文章正文内容,下面案例可供参考
一、语法实现
@Select("SELECT * FROM " +
"blog WHERE id = #{id}")
@ConstructorArgs({
@Arg(column = "id", javaType = int.class, id = true),
@Arg(column = "title", javaType = String.class),
@Arg(column = "author_id", javaType = Author.class, select = "org.apache.ibatis.binding.BoundAuthorMapper.selectAuthor"),
@Arg(column = "id", javaType = List.class, select = "selectPostsForBlog")
})
Blog selectBlogUsingConstructor(int id);
二、实现原理
一般一个注解只能在一个地方,加了这个注解,表明了可以@Arg,可以在@ConstructArgs里使用多次。那么,此注解究竟是怎么实现了嵌套的查询,很好奇,下面我将通过源码一步一步揭开Mybaits内部的神秘面纱…
2.1 @Arg里面的column值代表了什么?
返回值Blog对象,有四个属性并没有跟我们的注解@Arg里面的column属性对应,有没有一种可能是在代码里进行了转换?
调用的过程是这样的,首先通过代理技术创建了mapper的代理对象,因为返回的是一个对象所以调用的是selectOne的方法,selelctOne调用的又是selectList的方法,通过statement,查询到了MappedStatement对象,我们看MappedStatement通过解析xml标签,mapper接口上面的注解给我们构造了怎样的映射对象,在ResultMaps里面我们看到ResultMapping对象里的property属性依然为空,所以我们可以推断并没有在构建configuration对象的时候将在@Arg里面的column属性进行映射成我们的要返回对象的属性。接着往下看…
接着就是利用excutor开始一大堆的查询,先判断是否开启了二级缓存,开启了二级缓存的话先去查询二级缓存,然后没有开启的话就去调用queryFromDataBase()方法,注意这个方法名虽然从表面上看是从数据库查询,其实也是先查询的一级缓存没有的话然后再去查数据库,利用statement对象去执行解析好的SQL,实际就是调用的JDBC的接口,然后对返回的数据进行处理,下面我们来到了对行数据的处理方法中…
请注意,这个方法已经返回了我们想要的对象,哪几个属性都赋值了,但是我们还有搞清楚到底column对象是怎么跟Blog对象的属性进行对应的,下面我们到这个方法里面查看
创建参数化返回的对象,这里的author_id不就是我们在@Arg注解里面定义的colun参数的值吗,然后判断这个嵌套查询的id不为null就开启了嵌套子查询
等等… 这个嵌套查询的id是什么鬼?我们打着打破沙岗问到底,问问公鸡几条腿的精神,继续探索…
原来是在这里构建ResultMapping对象的时候利用构建者模式构建的,那么为啥有的为null而就知道author_id有值了呢?
继续往下看…
这里传了这么一个参数,这个参数哪里来的呢?
原来就是我们@Arg注解里面的select属性,真相大白…