MyBatis源码分析(05)执行查询SQL

前面的获取对象的过程基本都debug完了,下面看最后一行:

String name = mapper.selectNameById(1);

也就是执行SQL语句的具体过程。





下面从SQL语句的执行开始debug:

1、String name = mapper.selectNameById(1);

我们自定义的接口UserMapper是个接口,没有实现类,前面分析获取mapper时我们知道,mybatis会为mapper类生成代理类,生成代理类的方法是使用MapperProxyFactory工厂类生成,代理的类其实就是MapperProxy,所以我们要看下一步的执行过程就要进入这个类进行查看,

1、String name = mapper.selectNameById(1);

2、org.apache.ibatis.binding.MapperProxy#invoke

其中第一个if判断 if (Object.class.equals(method.getDeclaringClass()))  ,这个MapperProxy就是一个InvocationHandler(他的作用是jdk创建动态代理时用的,没印象的可以复习一下),也就是我们会根据当前的接口创建一个这个接口的动态代理对象,使用动态代理对象再利用反射调用实际对象的目标方法。

然而动态代理对象里面的方法都是Interface规定的。但是动态代理对象也能调用比如toString(),hashCode()等这些方法呀,这些方法是所有类从Object继承过来的。

所以这个判断的根本作用就是,如果利用动态代理对象调用的是toString,hashCode,getClass等这些从Object类继承过来的方法,就直接反射调用。如果调用的是接口规定的方法。我们就用MapperMethod来执行。所以这个判断是十分必要的。

继续看下面的方法,判断出不是Object的方法,是接口的方法,所以执行下面的代码,从cachedMapperMethod中获取要执行的方法:

1、String name = mapper.selectNameById(1);

2、org.apache.ibatis.binding.MapperProxy#invoke

3、org.apache.ibatis.binding.MapperProxy#cachedMapperMethod

这是个典型的从缓存中获取方法对象的代码,如果缓存中没有,就新建并加入缓存,最后返回这个方法,methodCache对象是一个map,存储了创建过的方法对象,创建的方式是根据接口,方法和配置对象进行创建。到这里我们就获取了我们实际要执行的方法的对象了。

现在我们回来继续看第二步,回到org.apache.ibatis.binding.MapperProxy#invoke方法中,

最后一行代码return中执行的,就是真正操作数据库的方法。我们继续看下一步:

1、String name = mapper.selectNameById(1);

2、org.apache.ibatis.binding.MapperProxy#invoke

3、org.apache.ibatis.binding.MapperProxy#cachedMapperMethod

4、org.apache.ibatis.binding.MapperMethod#execute

进入这个方法可以看到,内容很丰富,开始是一个判断语句块,判断当前的操作是什么类型,我们通过idea来看一下正在执行的是什么类型:

如果是增删改的话,执行方式比较一致和简单,

准备好参数然后去执行,本次执行的是查询操作,所以我们主要看下面的SELECT:

查询操作通过判断返回的类型,执行对应的方法,前面几种是比较经典的返回类型,如果都不满足,就会执行else内的方法,本次的selectNameById方法执行的就是else中的内容:

第一行是转换参数为SQL命令中的形式,下面这一行是关键,真正执行的是sqlSession.selectOne方法,我们在前面讨论获取sqlSession对象的源码的时候,查看了SqlSession类中的方法,这是其中一个。传入的第一个参数就是方法:

第二个就是参数,下面我进入这个方法,查看流程:

1、String name = mapper.selectNameById(1);

2、org.apache.ibatis.binding.MapperProxy#invoke

3、org.apache.ibatis.binding.MapperProxy#cachedMapperMethod

4、org.apache.ibatis.binding.MapperMethod#execute

5、org.apache.ibatis.session.defaults.DefaultSqlSession#selectOne(java.lang.String, java.lang.Object)

我们在使用mybatis的时候,用的是官方文档建议的方法,获取mapper对象,使用mapper对象执行我们自定义的数据库操作方法。官方文档上还有另一种调用方法:

就是直接调用sqlSession中的方法,上面图片例子中的两个参数就是我们前面的过程在组合的参数,也就是说获取mapper对象执行方法最终的过程也是执行sqlSession中的内容,和上面这种方法殊途同归。我们继续来看selectOne中的内容,selectOne最终的执行过程也是执行selectList查询一个列表,然后获取列表中的第一个元素,继续看selectList方法:

1、String name = mapper.selectNameById(1);

2、org.apache.ibatis.binding.MapperProxy#invoke

3、org.apache.ibatis.binding.MapperProxy#cachedMapperMethod

4、org.apache.ibatis.binding.MapperMethod#execute

5、org.apache.ibatis.session.defaults.DefaultSqlSession#selectOne(java.lang.String, java.lang.Object)

6、org.apache.ibatis.session.defaults.DefaultSqlSession#selectList(java.lang.String, java.lang.Object)

这里加了一个方法参数,RowBounds.DEFAULT,这是物理分页传入的默认参数,返回的结果其实分页了,但是和没分页效果一样,下面继续调用:

1、String name = mapper.selectNameById(1);

2、org.apache.ibatis.binding.MapperProxy#invoke

3、org.apache.ibatis.binding.MapperProxy#cachedMapperMethod

4、org.apache.ibatis.binding.MapperMethod#execute

5、org.apache.ibatis.session.defaults.DefaultSqlSession#selectOne(java.lang.String, java.lang.Object)

6、org.apache.ibatis.session.defaults.DefaultSqlSession#selectList(java.lang.String, java.lang.Object)

7、org.apache.ibatis.session.defaults.DefaultSqlSession#selectList(java.lang.String, java.lang.Object, org.apache.ibatis.session.RowBounds)

我们在执行jdbc的时候,先编译SQL语句,获取一个Statement对象,这里获取的是一个MappedStatement对象,这个类对应的就是select标签。类的属性和select标签的属性一致。下面这一行executor.query方法执行操作,继续看下面的代码,使用Executor的对象执行,Executor是一个接口,有两个实现类,通过工具可以看到这里使用的是CachingExecutor类的对象实例执行的:

1、String name = mapper.selectNameById(1);

2、org.apache.ibatis.binding.MapperProxy#invoke

3、org.apache.ibatis.binding.MapperProxy#cachedMapperMethod

4、org.apache.ibatis.binding.MapperMethod#execute

5、org.apache.ibatis.session.defaults.DefaultSqlSession#selectOne(java.lang.String, java.lang.Object)

6、org.apache.ibatis.session.defaults.DefaultSqlSession#selectList(java.lang.String, java.lang.Object)

7、org.apache.ibatis.session.defaults.DefaultSqlSession#selectList(java.lang.String, java.lang.Object, org.apache.ibatis.session.RowBounds)

8、org.apache.ibatis.executor.CachingExecutor#query(org.apache.ibatis.mapping.MappedStatement, java.lang.Object, org.apache.ibatis.session.RowBounds, org.apache.ibatis.session.ResultHandler)

通过类名我们可以猜测到,这个Executor执行类是使用内存的,将数据保存到缓存中,这样可以有效的解决增删改查性能。缓存的作用域为mapper(namespace),所以同一个namespace的操作会影响到相同作用域下的缓存,这样不同的域对同一个表进行操作很有可能导致缓存中的数据不一样,出现问题,还是不推荐使用。我们看方法的内容:

前面两行是创建缓存值,获取记录,继续往下看:

1、String name = mapper.selectNameById(1);

2、org.apache.ibatis.binding.MapperProxy#invoke

3、org.apache.ibatis.binding.MapperProxy#cachedMapperMethod

4、org.apache.ibatis.binding.MapperMethod#execute

5、org.apache.ibatis.session.defaults.DefaultSqlSession#selectOne(java.lang.String, java.lang.Object)

6、org.apache.ibatis.session.defaults.DefaultSqlSession#selectList(java.lang.String, java.lang.Object)

7、org.apache.ibatis.session.defaults.DefaultSqlSession#selectList(java.lang.String, java.lang.Object, org.apache.ibatis.session.RowBounds)

8、org.apache.ibatis.executor.CachingExecutor#query(org.apache.ibatis.mapping.MappedStatement, java.lang.Object, org.apache.ibatis.session.RowBounds, org.apache.ibatis.session.ResultHandler)

9、org.apache.ibatis.executor.CachingExecutor#query(org.apache.ibatis.mapping.MappedStatement, java.lang.Object, org.apache.ibatis.session.RowBounds, org.apache.ibatis.session.ResultHandler, org.apache.ibatis.cache.CacheKey, org.apache.ibatis.mapping.BoundSql)

上面这个过程就是一级缓存的内容,如果缓存里不为空,就从缓存中查询,如果缓存为空,就查询数据库,这里启动程序只进行一次查询,所以会走查询数据库的分支,最后一行的delegate对象,也是一个Executor对象,这里走不使用缓存的分支,执行操作使用的BaseExecutor对象:

1、String name = mapper.selectNameById(1);

2、org.apache.ibatis.binding.MapperProxy#invoke

3、org.apache.ibatis.binding.MapperProxy#cachedMapperMethod

4、org.apache.ibatis.binding.MapperMethod#execute

5、org.apache.ibatis.session.defaults.DefaultSqlSession#selectOne(java.lang.String, java.lang.Object)

6、org.apache.ibatis.session.defaults.DefaultSqlSession#selectList(java.lang.String, java.lang.Object)

7、org.apache.ibatis.session.defaults.DefaultSqlSession#selectList(java.lang.String, java.lang.Object, org.apache.ibatis.session.RowBounds)

8、org.apache.ibatis.executor.CachingExecutor#query(org.apache.ibatis.mapping.MappedStatement, java.lang.Object, org.apache.ibatis.session.RowBounds, org.apache.ibatis.session.ResultHandler)

9、org.apache.ibatis.executor.CachingExecutor#query(org.apache.ibatis.mapping.MappedStatement, java.lang.Object, org.apache.ibatis.session.RowBounds, org.apache.ibatis.session.ResultHandler, org.apache.ibatis.cache.CacheKey, org.apache.ibatis.mapping.BoundSql)

10、org.apache.ibatis.executor.BaseExecutor#query(org.apache.ibatis.mapping.MappedStatement, java.lang.Object, org.apache.ibatis.session.RowBounds, org.apache.ibatis.session.ResultHandler, org.apache.ibatis.cache.CacheKey, org.apache.ibatis.mapping.BoundSql)

这里从数据库查,走的是:

list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);

这条代码分支,从名字可以看出从数据库查询,参数中传了很多,除了编译好的SQL,还有分页,结果的handler,等等,这些是mybatis封装jdbc后以自己的特色去执行SQL的方式,这种麻烦的方法简化了我们使用mybatis的方式,下面继续看:

1、String name = mapper.selectNameById(1);

2、org.apache.ibatis.binding.MapperProxy#invoke

3、org.apache.ibatis.binding.MapperProxy#cachedMapperMethod

4、org.apache.ibatis.binding.MapperMethod#execute

5、org.apache.ibatis.session.defaults.DefaultSqlSession#selectOne(java.lang.String, java.lang.Object)

6、org.apache.ibatis.session.defaults.DefaultSqlSession#selectList(java.lang.String, java.lang.Object)

7、org.apache.ibatis.session.defaults.DefaultSqlSession#selectList(java.lang.String, java.lang.Object, org.apache.ibatis.session.RowBounds)

8、org.apache.ibatis.executor.CachingExecutor#query(org.apache.ibatis.mapping.MappedStatement, java.lang.Object, org.apache.ibatis.session.RowBounds, org.apache.ibatis.session.ResultHandler)

9、org.apache.ibatis.executor.CachingExecutor#query(org.apache.ibatis.mapping.MappedStatement, java.lang.Object, org.apache.ibatis.session.RowBounds, org.apache.ibatis.session.ResultHandler, org.apache.ibatis.cache.CacheKey, org.apache.ibatis.mapping.BoundSql)

10、org.apache.ibatis.executor.BaseExecutor#query(org.apache.ibatis.mapping.MappedStatement, java.lang.Object, org.apache.ibatis.session.RowBounds, org.apache.ibatis.session.ResultHandler, org.apache.ibatis.cache.CacheKey, org.apache.ibatis.mapping.BoundSql)

11、org.apache.ibatis.executor.BaseExecutor#queryFromDatabase

看代码:

localCache.putObject(key, EXECUTION_PLACEHOLDER);

这里查询了一次以后,加入了一级缓存当中,下面就是执行doQuery方法:

1、String name = mapper.selectNameById(1);

2、org.apache.ibatis.binding.MapperProxy#invoke

3、org.apache.ibatis.binding.MapperProxy#cachedMapperMethod

4、org.apache.ibatis.binding.MapperMethod#execute

5、org.apache.ibatis.session.defaults.DefaultSqlSession#selectOne(java.lang.String, java.lang.Object)

6、org.apache.ibatis.session.defaults.DefaultSqlSession#selectList(java.lang.String, java.lang.Object)

7、org.apache.ibatis.session.defaults.DefaultSqlSession#selectList(java.lang.String, java.lang.Object, org.apache.ibatis.session.RowBounds)

8、org.apache.ibatis.executor.CachingExecutor#query(org.apache.ibatis.mapping.MappedStatement, java.lang.Object, org.apache.ibatis.session.RowBounds, org.apache.ibatis.session.ResultHandler)

9、org.apache.ibatis.executor.CachingExecutor#query(org.apache.ibatis.mapping.MappedStatement, java.lang.Object, org.apache.ibatis.session.RowBounds, org.apache.ibatis.session.ResultHandler, org.apache.ibatis.cache.CacheKey, org.apache.ibatis.mapping.BoundSql)

10、org.apache.ibatis.executor.BaseExecutor#query(org.apache.ibatis.mapping.MappedStatement, java.lang.Object, org.apache.ibatis.session.RowBounds, org.apache.ibatis.session.ResultHandler, org.apache.ibatis.cache.CacheKey, org.apache.ibatis.mapping.BoundSql)

11、org.apache.ibatis.executor.BaseExecutor#queryFromDatabase

12、org.apache.ibatis.executor.SimpleExecutor#doQuery

这里进入了SimpleExecutor类中,第一行的Statement stmt =null;代码有点眼熟,就是我们jdbc中的Statement 对象,说明我们马上要接近真相了!继续,前面三个是对SQL语句进行预编译,然后执行query方法,通过debug,知道下一步执行这个方法:

1、String name = mapper.selectNameById(1);

2、org.apache.ibatis.binding.MapperProxy#invoke

3、org.apache.ibatis.binding.MapperProxy#cachedMapperMethod

4、org.apache.ibatis.binding.MapperMethod#execute

5、org.apache.ibatis.session.defaults.DefaultSqlSession#selectOne(java.lang.String, java.lang.Object)

6、org.apache.ibatis.session.defaults.DefaultSqlSession#selectList(java.lang.String, java.lang.Object)

7、org.apache.ibatis.session.defaults.DefaultSqlSession#selectList(java.lang.String, java.lang.Object, org.apache.ibatis.session.RowBounds)

8、org.apache.ibatis.executor.CachingExecutor#query(org.apache.ibatis.mapping.MappedStatement, java.lang.Object, org.apache.ibatis.session.RowBounds, org.apache.ibatis.session.ResultHandler)

9、org.apache.ibatis.executor.CachingExecutor#query(org.apache.ibatis.mapping.MappedStatement, java.lang.Object, org.apache.ibatis.session.RowBounds, org.apache.ibatis.session.ResultHandler, org.apache.ibatis.cache.CacheKey, org.apache.ibatis.mapping.BoundSql)

10、org.apache.ibatis.executor.BaseExecutor#query(org.apache.ibatis.mapping.MappedStatement, java.lang.Object, org.apache.ibatis.session.RowBounds, org.apache.ibatis.session.ResultHandler, org.apache.ibatis.cache.CacheKey, org.apache.ibatis.mapping.BoundSql)

11、org.apache.ibatis.executor.BaseExecutor#queryFromDatabase

12、org.apache.ibatis.executor.SimpleExecutor#doQuery

13、org.apache.ibatis.executor.statement.RoutingStatementHandler#query

这里就是一行调用,继续debug:

1、String name = mapper.selectNameById(1);

2、org.apache.ibatis.binding.MapperProxy#invoke

3、org.apache.ibatis.binding.MapperProxy#cachedMapperMethod

4、org.apache.ibatis.binding.MapperMethod#execute

5、org.apache.ibatis.session.defaults.DefaultSqlSession#selectOne(java.lang.String, java.lang.Object)

6、org.apache.ibatis.session.defaults.DefaultSqlSession#selectList(java.lang.String, java.lang.Object)

7、org.apache.ibatis.session.defaults.DefaultSqlSession#selectList(java.lang.String, java.lang.Object, org.apache.ibatis.session.RowBounds)

8、org.apache.ibatis.executor.CachingExecutor#query(org.apache.ibatis.mapping.MappedStatement, java.lang.Object, org.apache.ibatis.session.RowBounds, org.apache.ibatis.session.ResultHandler)

9、org.apache.ibatis.executor.CachingExecutor#query(org.apache.ibatis.mapping.MappedStatement, java.lang.Object, org.apache.ibatis.session.RowBounds, org.apache.ibatis.session.ResultHandler, org.apache.ibatis.cache.CacheKey, org.apache.ibatis.mapping.BoundSql)

10、org.apache.ibatis.executor.BaseExecutor#query(org.apache.ibatis.mapping.MappedStatement, java.lang.Object, org.apache.ibatis.session.RowBounds, org.apache.ibatis.session.ResultHandler, org.apache.ibatis.cache.CacheKey, org.apache.ibatis.mapping.BoundSql)

11、org.apache.ibatis.executor.BaseExecutor#queryFromDatabase

12、org.apache.ibatis.executor.SimpleExecutor#doQuery

13、org.apache.ibatis.executor.statement.RoutingStatementHandler#query

14、org.apache.ibatis.executor.statement.PreparedStatementHandler#query

第一行是jdk中jdbc的类,执行获取预编译操作,然后执行了ps.execute();,这个就是我们的jdbc方法!终于到这里了!resultSetHandler是mybatis的对象,包装jdbc的结果,我们继续看:

1、String name = mapper.selectNameById(1);

2、org.apache.ibatis.binding.MapperProxy#invoke

3、org.apache.ibatis.binding.MapperProxy#cachedMapperMethod

4、org.apache.ibatis.binding.MapperMethod#execute

5、org.apache.ibatis.session.defaults.DefaultSqlSession#selectOne(java.lang.String, java.lang.Object)

6、org.apache.ibatis.session.defaults.DefaultSqlSession#selectList(java.lang.String, java.lang.Object)

7、org.apache.ibatis.session.defaults.DefaultSqlSession#selectList(java.lang.String, java.lang.Object, org.apache.ibatis.session.RowBounds)

8、org.apache.ibatis.executor.CachingExecutor#query(org.apache.ibatis.mapping.MappedStatement, java.lang.Object, org.apache.ibatis.session.RowBounds, org.apache.ibatis.session.ResultHandler)

9、org.apache.ibatis.executor.CachingExecutor#query(org.apache.ibatis.mapping.MappedStatement, java.lang.Object, org.apache.ibatis.session.RowBounds, org.apache.ibatis.session.ResultHandler, org.apache.ibatis.cache.CacheKey, org.apache.ibatis.mapping.BoundSql)

10、org.apache.ibatis.executor.BaseExecutor#query(org.apache.ibatis.mapping.MappedStatement, java.lang.Object, org.apache.ibatis.session.RowBounds, org.apache.ibatis.session.ResultHandler, org.apache.ibatis.cache.CacheKey, org.apache.ibatis.mapping.BoundSql)

11、org.apache.ibatis.executor.BaseExecutor#queryFromDatabase

12、org.apache.ibatis.executor.SimpleExecutor#doQuery

13、org.apache.ibatis.executor.statement.RoutingStatementHandler#query

14、org.apache.ibatis.executor.statement.PreparedStatementHandler#query

15、org.apache.ibatis.executor.resultset.DefaultResultSetHandler#handleResultSets

ResultSetHandler负责处理两件事,一是处理Statement执行后产生的结果集,生成结果列表,二是处理存储过程执行后的输出参数。DefaultResultSetHandler类是ResultSetHandler的默认实现,这里执行了这个类的handleResultSets方法,其实现的步骤就是将Statement执行后的结果集,按照Mapper文件中配置的ResultType或ResultMap来封装成对应的对象,最后将封装的对象返回即可,这里有一行代码:

ResultSetWrapper rsw = getFirstResultSet(stmt);

我们进入getFirstResultSet方法看一看:

这里的代码很眼熟了,就是jdbc接收结果的过程,最后一行把这个结果封装成了mybatis中的结果对象,封装的过程如下:

这里面包含的记过的很多熟悉,类型,名称,对象的类型,等等。我们继续来看handleResultSets方法,组合好多个返回结果的list后,我们看最后一行代码,执行collapseSingleResultList方法:

1、String name = mapper.selectNameById(1);

2、org.apache.ibatis.binding.MapperProxy#invoke

3、org.apache.ibatis.binding.MapperProxy#cachedMapperMethod

4、org.apache.ibatis.binding.MapperMethod#execute

5、org.apache.ibatis.session.defaults.DefaultSqlSession#selectOne(java.lang.String, java.lang.Object)

6、org.apache.ibatis.session.defaults.DefaultSqlSession#selectList(java.lang.String, java.lang.Object)

7、org.apache.ibatis.session.defaults.DefaultSqlSession#selectList(java.lang.String, java.lang.Object, org.apache.ibatis.session.RowBounds)

8、org.apache.ibatis.executor.CachingExecutor#query(org.apache.ibatis.mapping.MappedStatement, java.lang.Object, org.apache.ibatis.session.RowBounds, org.apache.ibatis.session.ResultHandler)

9、org.apache.ibatis.executor.CachingExecutor#query(org.apache.ibatis.mapping.MappedStatement, java.lang.Object, org.apache.ibatis.session.RowBounds, org.apache.ibatis.session.ResultHandler, org.apache.ibatis.cache.CacheKey, org.apache.ibatis.mapping.BoundSql)

10、org.apache.ibatis.executor.BaseExecutor#query(org.apache.ibatis.mapping.MappedStatement, java.lang.Object, org.apache.ibatis.session.RowBounds, org.apache.ibatis.session.ResultHandler, org.apache.ibatis.cache.CacheKey, org.apache.ibatis.mapping.BoundSql)

11、org.apache.ibatis.executor.BaseExecutor#queryFromDatabase

12、org.apache.ibatis.executor.SimpleExecutor#doQuery

13、org.apache.ibatis.executor.statement.RoutingStatementHandler#query

14、org.apache.ibatis.executor.statement.PreparedStatementHandler#query

15、org.apache.ibatis.executor.resultset.DefaultResultSetHandler#handleResultSets

16、org.apache.ibatis.executor.resultset.DefaultResultSetHandler#collapseSingleResultList

从判断可以看出,在判断是不是只有一条结果,这样封装返回结果的对象就执行完了。我们再次返回前面的方法:

1、String name = mapper.selectNameById(1);

2、org.apache.ibatis.binding.MapperProxy#invoke

3、org.apache.ibatis.binding.MapperProxy#cachedMapperMethod

4、org.apache.ibatis.binding.MapperMethod#execute

5、org.apache.ibatis.session.defaults.DefaultSqlSession#selectOne(java.lang.String, java.lang.Object)

6、org.apache.ibatis.session.defaults.DefaultSqlSession#selectList(java.lang.String, java.lang.Object)

7、org.apache.ibatis.session.defaults.DefaultSqlSession#selectList(java.lang.String, java.lang.Object, org.apache.ibatis.session.RowBounds)

8、org.apache.ibatis.executor.CachingExecutor#query(org.apache.ibatis.mapping.MappedStatement, java.lang.Object, org.apache.ibatis.session.RowBounds, org.apache.ibatis.session.ResultHandler)

9、org.apache.ibatis.executor.CachingExecutor#query(org.apache.ibatis.mapping.MappedStatement, java.lang.Object, org.apache.ibatis.session.RowBounds, org.apache.ibatis.session.ResultHandler, org.apache.ibatis.cache.CacheKey, org.apache.ibatis.mapping.BoundSql)

10、org.apache.ibatis.executor.BaseExecutor#query(org.apache.ibatis.mapping.MappedStatement, java.lang.Object, org.apache.ibatis.session.RowBounds, org.apache.ibatis.session.ResultHandler, org.apache.ibatis.cache.CacheKey, org.apache.ibatis.mapping.BoundSql)

11、org.apache.ibatis.executor.BaseExecutor#queryFromDatabase

12、org.apache.ibatis.executor.SimpleExecutor#doQuery

13、org.apache.ibatis.executor.statement.RoutingStatementHandler#query

14、org.apache.ibatis.executor.statement.PreparedStatementHandler#query

15、org.apache.ibatis.executor.resultset.DefaultResultSetHandler#handleResultSets

16、org.apache.ibatis.executor.resultset.DefaultResultSetHandler#collapseSingleResultList

17、org.apache.ibatis.executor.statement.PreparedStatementHandler#query

这里是前面的方法,返回的就是符合类型的结果的list,无论一条还是多条,继续debug:

1、String name = mapper.selectNameById(1);

2、org.apache.ibatis.binding.MapperProxy#invoke

3、org.apache.ibatis.binding.MapperProxy#cachedMapperMethod

4、org.apache.ibatis.binding.MapperMethod#execute

5、org.apache.ibatis.session.defaults.DefaultSqlSession#selectOne(java.lang.String, java.lang.Object)

6、org.apache.ibatis.session.defaults.DefaultSqlSession#selectList(java.lang.String, java.lang.Object)

7、org.apache.ibatis.session.defaults.DefaultSqlSession#selectList(java.lang.String, java.lang.Object, org.apache.ibatis.session.RowBounds)

8、org.apache.ibatis.executor.CachingExecutor#query(org.apache.ibatis.mapping.MappedStatement, java.lang.Object, org.apache.ibatis.session.RowBounds, org.apache.ibatis.session.ResultHandler)

9、org.apache.ibatis.executor.CachingExecutor#query(org.apache.ibatis.mapping.MappedStatement, java.lang.Object, org.apache.ibatis.session.RowBounds, org.apache.ibatis.session.ResultHandler, org.apache.ibatis.cache.CacheKey, org.apache.ibatis.mapping.BoundSql)

10、org.apache.ibatis.executor.BaseExecutor#query(org.apache.ibatis.mapping.MappedStatement, java.lang.Object, org.apache.ibatis.session.RowBounds, org.apache.ibatis.session.ResultHandler, org.apache.ibatis.cache.CacheKey, org.apache.ibatis.mapping.BoundSql)

11、org.apache.ibatis.executor.BaseExecutor#queryFromDatabase

12、org.apache.ibatis.executor.SimpleExecutor#doQuery

13、org.apache.ibatis.executor.statement.RoutingStatementHandler#query

14、org.apache.ibatis.executor.statement.PreparedStatementHandler#query

15、org.apache.ibatis.executor.resultset.DefaultResultSetHandler#handleResultSets

16、org.apache.ibatis.executor.resultset.DefaultResultSetHandler#collapseSingleResultList

17、org.apache.ibatis.executor.statement.PreparedStatementHandler#query

18、org.apache.ibatis.executor.statement.RoutingStatementHandler#query

继续往回执行:

1、String name = mapper.selectNameById(1);

2、org.apache.ibatis.binding.MapperProxy#invoke

3、org.apache.ibatis.binding.MapperProxy#cachedMapperMethod

4、org.apache.ibatis.binding.MapperMethod#execute

5、org.apache.ibatis.session.defaults.DefaultSqlSession#selectOne(java.lang.String, java.lang.Object)

6、org.apache.ibatis.session.defaults.DefaultSqlSession#selectList(java.lang.String, java.lang.Object)

7、org.apache.ibatis.session.defaults.DefaultSqlSession#selectList(java.lang.String, java.lang.Object, org.apache.ibatis.session.RowBounds)

8、org.apache.ibatis.executor.CachingExecutor#query(org.apache.ibatis.mapping.MappedStatement, java.lang.Object, org.apache.ibatis.session.RowBounds, org.apache.ibatis.session.ResultHandler)

9、org.apache.ibatis.executor.CachingExecutor#query(org.apache.ibatis.mapping.MappedStatement, java.lang.Object, org.apache.ibatis.session.RowBounds, org.apache.ibatis.session.ResultHandler, org.apache.ibatis.cache.CacheKey, org.apache.ibatis.mapping.BoundSql)

10、org.apache.ibatis.executor.BaseExecutor#query(org.apache.ibatis.mapping.MappedStatement, java.lang.Object, org.apache.ibatis.session.RowBounds, org.apache.ibatis.session.ResultHandler, org.apache.ibatis.cache.CacheKey, org.apache.ibatis.mapping.BoundSql)

11、org.apache.ibatis.executor.BaseExecutor#queryFromDatabase

12、org.apache.ibatis.executor.SimpleExecutor#doQuery

13、org.apache.ibatis.executor.statement.RoutingStatementHandler#query

14、org.apache.ibatis.executor.statement.PreparedStatementHandler#query

15、org.apache.ibatis.executor.resultset.DefaultResultSetHandler#handleResultSets

16、org.apache.ibatis.executor.resultset.DefaultResultSetHandler#collapseSingleResultList

17、org.apache.ibatis.executor.statement.PreparedStatementHandler#query

18、org.apache.ibatis.executor.statement.RoutingStatementHandler#query

19、org.apache.ibatis.executor.SimpleExecutor#doQuery

继续往回执行:

1、String name = mapper.selectNameById(1);

2、org.apache.ibatis.binding.MapperProxy#invoke

3、org.apache.ibatis.binding.MapperProxy#cachedMapperMethod

4、org.apache.ibatis.binding.MapperMethod#execute

5、org.apache.ibatis.session.defaults.DefaultSqlSession#selectOne(java.lang.String, java.lang.Object)

6、org.apache.ibatis.session.defaults.DefaultSqlSession#selectList(java.lang.String, java.lang.Object)

7、org.apache.ibatis.session.defaults.DefaultSqlSession#selectList(java.lang.String, java.lang.Object, org.apache.ibatis.session.RowBounds)

8、org.apache.ibatis.executor.CachingExecutor#query(org.apache.ibatis.mapping.MappedStatement, java.lang.Object, org.apache.ibatis.session.RowBounds, org.apache.ibatis.session.ResultHandler)

9、org.apache.ibatis.executor.CachingExecutor#query(org.apache.ibatis.mapping.MappedStatement, java.lang.Object, org.apache.ibatis.session.RowBounds, org.apache.ibatis.session.ResultHandler, org.apache.ibatis.cache.CacheKey, org.apache.ibatis.mapping.BoundSql)

10、org.apache.ibatis.executor.BaseExecutor#query(org.apache.ibatis.mapping.MappedStatement, java.lang.Object, org.apache.ibatis.session.RowBounds, org.apache.ibatis.session.ResultHandler, org.apache.ibatis.cache.CacheKey, org.apache.ibatis.mapping.BoundSql)

11、org.apache.ibatis.executor.BaseExecutor#queryFromDatabase

12、org.apache.ibatis.executor.SimpleExecutor#doQuery

13、org.apache.ibatis.executor.statement.RoutingStatementHandler#query

14、org.apache.ibatis.executor.statement.PreparedStatementHandler#query

15、org.apache.ibatis.executor.resultset.DefaultResultSetHandler#handleResultSets

16、org.apache.ibatis.executor.resultset.DefaultResultSetHandler#collapseSingleResultList

17、org.apache.ibatis.executor.statement.PreparedStatementHandler#query

18、org.apache.ibatis.executor.statement.RoutingStatementHandler#query

19、org.apache.ibatis.executor.SimpleExecutor#doQuery

20、org.apache.ibatis.executor.BaseExecutor#queryFromDatabase

这里把最终的查询结果放到了一级缓存中,然后继续往回执行:

1、String name = mapper.selectNameById(1);

2、org.apache.ibatis.binding.MapperProxy#invoke

3、org.apache.ibatis.binding.MapperProxy#cachedMapperMethod

4、org.apache.ibatis.binding.MapperMethod#execute

5、org.apache.ibatis.session.defaults.DefaultSqlSession#selectOne(java.lang.String, java.lang.Object)

6、org.apache.ibatis.session.defaults.DefaultSqlSession#selectList(java.lang.String, java.lang.Object)

7、org.apache.ibatis.session.defaults.DefaultSqlSession#selectList(java.lang.String, java.lang.Object, org.apache.ibatis.session.RowBounds)

8、org.apache.ibatis.executor.CachingExecutor#query(org.apache.ibatis.mapping.MappedStatement, java.lang.Object, org.apache.ibatis.session.RowBounds, org.apache.ibatis.session.ResultHandler)

9、org.apache.ibatis.executor.CachingExecutor#query(org.apache.ibatis.mapping.MappedStatement, java.lang.Object, org.apache.ibatis.session.RowBounds, org.apache.ibatis.session.ResultHandler, org.apache.ibatis.cache.CacheKey, org.apache.ibatis.mapping.BoundSql)

10、org.apache.ibatis.executor.BaseExecutor#query(org.apache.ibatis.mapping.MappedStatement, java.lang.Object, org.apache.ibatis.session.RowBounds, org.apache.ibatis.session.ResultHandler, org.apache.ibatis.cache.CacheKey, org.apache.ibatis.mapping.BoundSql)

11、org.apache.ibatis.executor.BaseExecutor#queryFromDatabase

12、org.apache.ibatis.executor.SimpleExecutor#doQuery

13、org.apache.ibatis.executor.statement.RoutingStatementHandler#query

14、org.apache.ibatis.executor.statement.PreparedStatementHandler#query

15、org.apache.ibatis.executor.resultset.DefaultResultSetHandler#handleResultSets

16、org.apache.ibatis.executor.resultset.DefaultResultSetHandler#collapseSingleResultList

17、org.apache.ibatis.executor.statement.PreparedStatementHandler#query

18、org.apache.ibatis.executor.statement.RoutingStatementHandler#query

19、org.apache.ibatis.executor.SimpleExecutor#doQuery

20、org.apache.ibatis.executor.BaseExecutor#queryFromDatabase

21、org.apache.ibatis.executor.BaseExecutor#query(org.apache.ibatis.mapping.MappedStatement, java.lang.Object, org.apache.ibatis.session.RowBounds, org.apache.ibatis.session.ResultHandler, org.apache.ibatis.cache.CacheKey, org.apache.ibatis.mapping.BoundSql)

这里面对缓存最后进行处理,继续往回看:

1、String name = mapper.selectNameById(1);

2、org.apache.ibatis.binding.MapperProxy#invoke

3、org.apache.ibatis.binding.MapperProxy#cachedMapperMethod

4、org.apache.ibatis.binding.MapperMethod#execute

5、org.apache.ibatis.session.defaults.DefaultSqlSession#selectOne(java.lang.String, java.lang.Object)

6、org.apache.ibatis.session.defaults.DefaultSqlSession#selectList(java.lang.String, java.lang.Object)

7、org.apache.ibatis.session.defaults.DefaultSqlSession#selectList(java.lang.String, java.lang.Object, org.apache.ibatis.session.RowBounds)

8、org.apache.ibatis.executor.CachingExecutor#query(org.apache.ibatis.mapping.MappedStatement, java.lang.Object, org.apache.ibatis.session.RowBounds, org.apache.ibatis.session.ResultHandler)

9、org.apache.ibatis.executor.CachingExecutor#query(org.apache.ibatis.mapping.MappedStatement, java.lang.Object, org.apache.ibatis.session.RowBounds, org.apache.ibatis.session.ResultHandler, org.apache.ibatis.cache.CacheKey, org.apache.ibatis.mapping.BoundSql)

10、org.apache.ibatis.executor.BaseExecutor#query(org.apache.ibatis.mapping.MappedStatement, java.lang.Object, org.apache.ibatis.session.RowBounds, org.apache.ibatis.session.ResultHandler, org.apache.ibatis.cache.CacheKey, org.apache.ibatis.mapping.BoundSql)

11、org.apache.ibatis.executor.BaseExecutor#queryFromDatabase

12、org.apache.ibatis.executor.SimpleExecutor#doQuery

13、org.apache.ibatis.executor.statement.RoutingStatementHandler#query

14、org.apache.ibatis.executor.statement.PreparedStatementHandler#query

15、org.apache.ibatis.executor.resultset.DefaultResultSetHandler#handleResultSets

16、org.apache.ibatis.executor.resultset.DefaultResultSetHandler#collapseSingleResultList

17、org.apache.ibatis.executor.statement.PreparedStatementHandler#query

18、org.apache.ibatis.executor.statement.RoutingStatementHandler#query

19、org.apache.ibatis.executor.SimpleExecutor#doQuery

20、org.apache.ibatis.executor.BaseExecutor#queryFromDatabase

21、org.apache.ibatis.executor.BaseExecutor#query(org.apache.ibatis.mapping.MappedStatement, java.lang.Object, org.apache.ibatis.session.RowBounds, org.apache.ibatis.session.ResultHandler, org.apache.ibatis.cache.CacheKey, org.apache.ibatis.mapping.BoundSql)

22、org.apache.ibatis.executor.CachingExecutor#query(org.apache.ibatis.mapping.MappedStatement, java.lang.Object, org.apache.ibatis.session.RowBounds, org.apache.ibatis.session.ResultHandler, org.apache.ibatis.cache.CacheKey, org.apache.ibatis.mapping.BoundSql)

23、org.apache.ibatis.executor.CachingExecutor#query(org.apache.ibatis.mapping.MappedStatement, java.lang.Object, org.apache.ibatis.session.RowBounds, org.apache.ibatis.session.ResultHandler)

24、org.apache.ibatis.session.defaults.DefaultSqlSession#selectList(java.lang.String, java.lang.Object, org.apache.ibatis.session.RowBounds)

25、org.apache.ibatis.session.defaults.DefaultSqlSession#selectList(java.lang.String, java.lang.Object)

26、org.apache.ibatis.session.defaults.DefaultSqlSession#selectOne(java.lang.String, java.lang.Object)

最后带着list回到了selectOne这里,

查询成功以后,返回了第一个对象,下面是代理对象:

1、String name = mapper.selectNameById(1);

2、org.apache.ibatis.binding.MapperProxy#invoke

3、org.apache.ibatis.binding.MapperProxy#cachedMapperMethod

4、org.apache.ibatis.binding.MapperMethod#execute

5、org.apache.ibatis.session.defaults.DefaultSqlSession#selectOne(java.lang.String, java.lang.Object)

6、org.apache.ibatis.session.defaults.DefaultSqlSession#selectList(java.lang.String, java.lang.Object)

7、org.apache.ibatis.session.defaults.DefaultSqlSession#selectList(java.lang.String, java.lang.Object, org.apache.ibatis.session.RowBounds)

8、org.apache.ibatis.executor.CachingExecutor#query(org.apache.ibatis.mapping.MappedStatement, java.lang.Object, org.apache.ibatis.session.RowBounds, org.apache.ibatis.session.ResultHandler)

9、org.apache.ibatis.executor.CachingExecutor#query(org.apache.ibatis.mapping.MappedStatement, java.lang.Object, org.apache.ibatis.session.RowBounds, org.apache.ibatis.session.ResultHandler, org.apache.ibatis.cache.CacheKey, org.apache.ibatis.mapping.BoundSql)

10、org.apache.ibatis.executor.BaseExecutor#query(org.apache.ibatis.mapping.MappedStatement, java.lang.Object, org.apache.ibatis.session.RowBounds, org.apache.ibatis.session.ResultHandler, org.apache.ibatis.cache.CacheKey, org.apache.ibatis.mapping.BoundSql)

11、org.apache.ibatis.executor.BaseExecutor#queryFromDatabase

12、org.apache.ibatis.executor.SimpleExecutor#doQuery

13、org.apache.ibatis.executor.statement.RoutingStatementHandler#query

14、org.apache.ibatis.executor.statement.PreparedStatementHandler#query

15、org.apache.ibatis.executor.resultset.DefaultResultSetHandler#handleResultSets

16、org.apache.ibatis.executor.resultset.DefaultResultSetHandler#collapseSingleResultList

17、org.apache.ibatis.executor.statement.PreparedStatementHandler#query

18、org.apache.ibatis.executor.statement.RoutingStatementHandler#query

19、org.apache.ibatis.executor.SimpleExecutor#doQuery

20、org.apache.ibatis.executor.BaseExecutor#queryFromDatabase

21、org.apache.ibatis.executor.BaseExecutor#query(org.apache.ibatis.mapping.MappedStatement, java.lang.Object, org.apache.ibatis.session.RowBounds, org.apache.ibatis.session.ResultHandler, org.apache.ibatis.cache.CacheKey, org.apache.ibatis.mapping.BoundSql)

22、org.apache.ibatis.executor.CachingExecutor#query(org.apache.ibatis.mapping.MappedStatement, java.lang.Object, org.apache.ibatis.session.RowBounds, org.apache.ibatis.session.ResultHandler, org.apache.ibatis.cache.CacheKey, org.apache.ibatis.mapping.BoundSql)

23、org.apache.ibatis.executor.CachingExecutor#query(org.apache.ibatis.mapping.MappedStatement, java.lang.Object, org.apache.ibatis.session.RowBounds, org.apache.ibatis.session.ResultHandler) 

24、org.apache.ibatis.session.defaults.DefaultSqlSession#selectList(java.lang.String, java.lang.Object, org.apache.ibatis.session.RowBounds)

25、org.apache.ibatis.session.defaults.DefaultSqlSession#selectList(java.lang.String, java.lang.Object)

26、org.apache.ibatis.session.defaults.DefaultSqlSession#selectOne(java.lang.String, java.lang.Object)

27、org.apache.ibatis.binding.MapperMethod#execute

28、org.apache.ibatis.binding.MapperProxy#invoke

29、String name = mapper.selectNameById(1);

最终我们回到了调用的地方,返回了查询的name!




总结

来总结一下,通过debug看源码是一个不太会看源码的人的一个不错的方法,我们上面通过debug来查看了mybatis查询的整个过程,中间的一级缓存,涉及到的几种查询Executor,获取返回结果的ResultSetHandler,编译的StatementHandler,物理分页的RowBounds等等几个对象是如果对jdbc查询的整个过程进行润色的,查询的整个过程在这个源码分析中是最复杂的,正是由于这个复杂,我们才能轻松的使用mybatis!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,271评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,275评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,151评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,550评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,553评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,559评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,924评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,580评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,826评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,578评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,661评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,363评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,940评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,926评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,156评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,872评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,391评论 2 342