这篇文章是紧接着上一篇 Mapper扫描加载和mapper接口代理的注册 的,调用Mapper接口最终会回调到MapperProxy的invoke方法。
可以看到的是调用执行前创建一个MapperMethod这个对象。然后调用cacehMapperMethod方法先缓存这个mapperCache这个map缓存中去,然后返回的MapperMethod, 最后执行它的execute方法。
从中看到execute方法,先判断sqlcommand的操作类型,然后执行对应的case, 这里选取SELECT且返回多个对象类别为例,进行一次数据的查询过程调用的过程的分析。所以它会执行method.returnMany()这个分支,调用executeForMany这个方法,
首先,解析转化参数为Map键值对的参数,如果没有RowBoud这个参数,就直接执行sqlSession.selectList方法,这里command的name就类全名+方法名,这里的sqlSession是SqlSessionTemplate的实例,这个是在下面的这个代码注入的
接下来执行拦截器插件,回调下面这段代码它的SqlSessionIntercceptor的invoke方法,
执行完拦截器后,再接着调用DefaultSqlSession的selectList方法
从Configuration中获取的MapperStatement这个对象,这个mapperStatement是在Mapper扫描的时候注入到Configureation中的,(这个回头在补上这个分析),然后交给 Executor去执行,这里看一下执行器的类,有执行器的策略,调试是发现注入的是CacheExecutor这个实例,具体看一下query方法,
上面这段是DefaultSqlSession的query方法,mapperStqtement调用getBoundSql这个方法传入参数对象返回一个BoundSql对象,这个对象是处理sql的类。
可以看出BoundSql是由sqlSource这个类,实际传入的对象RawSqlSource这个类的实例,然后获取参数映射,然后回到query方法继续执行,创建缓存的key,下面来创建缓存的key。
可以看到缓存的key的生成规则是:由MapperStatement的id,boundSql的偏移量、limit、sql以及参数值,hash= 37 * hashcode + basehashcode, CacheExecutor里面委托一个SimpleExecutor执行,具体的CRUD操作,接着的执行SimpleExecutor的query方法,
这里通过生成cacheKey获取的Cache,这个Cache就是mybatis的二级缓存,如果缓存存在,先执行flushCache,如果有使用缓存,则直接返回,如果cache是空的,则直接调用SimpleExecutor的query的方法,如下图所示:
这个方法中首先是从二级缓存中取,如果没有,则执行queryFromDatabase方法从数据库中查询数据。如果有,则这届从缓存中取,还要处理当StatementType 是Callable的输入参数9这里调用数据库的存储过程的类型的配置),,当一次查询的session的queryStach等于0,就是代表一次session数据库的交互借宿,如果configuration配置的localCacheScope是LocalCacheScope.STATEMENT,则清除localCache的数据。
queryFromDataBase中首先先缓存一个EXECUTION_PLACEHOLDER这个枚举值,接着执行SimpleExecutor的方法的doQuery方法,接着删除localCache中的key, 这样做主要是避免并发操作数据库的时候,都去访问数据库。doQuery查询完成后就去将数据缓存到这个localCache中,最后一句是缓存存储过程的输出参数的。暂时可以忽略,这里暂时分析sql的执行。
doQuery方法首先是通过Configuration获取创建一个StatementHandler,这里创建的是PrepareStatementHandler,然后在执行statementHandler的query方法。
这列执行prepareStatementLogger执行execute方法,通过注入的DefaultResultSetHandler实例调用handlerResultSets方法转换数据集,返回查询的数据集。
总结: 本篇文章主要介绍mapper的动态代理的调用过程,sqlsesionTemlate的执行select的处理过程,后面还有很多细节需要完善。