mybatis接口是编程是利用jdk动态来实现的
1.代理对象不管执行哪个方法都会执行mapperProxy的invoke方法,判断当前执行器的方法是否是Object类的方法,因为代理对象的方法一部分是从需要代理的接口中实现过来的,另一部分是Object里面的方法比如equals、toString等方法。
2.接着将Method包装成MapperMethod对象,该对象包含sqlCommand和MegthodSignature两个对象,sqlCommand(在初始该对象传入Configuration,接口的Class对象,Method进行初始化,调用自身的resolveMappedStatement方法获取拼接statementId,即接口的全路径名+方法名,调用Configuration.getMappedStatement方法获取MappedStatement对象,该对象维护了一条<select|update|delete|insert>节点的封装,这边很容看出sqlCommand初始化传入这三个参数的作用了,MegthodSignature存储了当前要调用方法的详细信息。
3.MapperMethod调用execute方法传入sqlsession和方法参数,先通过sqlCommand判断当前语句的类型。这里我们先讲查询返回对象的情况,mybatis会通过MegthodSignature对象判断当前要执行的方法返回的条数和类型,去执行相对应的方法。首先调用convertArgsToSqlCommandParam对当前执行的方法参数的解析,接着调用defaultSqlSession.selectOne(command.getName(), param)的方法。这里的command.getName()的值是statementId也就是我们开发配置的namespace加对应语句的id
接着调用this.selectList(statement, parameter)(这个this是defaultSqlSession)将查询的数据返回第一条出去。
这里来分析selectList方法,截图如下:
首先通过statement,(其实就是我们刚刚上面所说的statementId)从configuration获取MappedStatement对象。MappedStatement包装当前运行方法对应的sql语句以及其类型。接着调用executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER)
进一层包装执行方法的参数,逻辑分页对象以及MappedStatement对象。传入该方法中,调用CachingExecutor这个执行器里面query方法,判断当前是否有配置缓存。没有缓存默认调用SimpleExecutor里面的query方法。继续查看simpleExecutor.query方法,该方法会先从本地缓存中也就是一级缓存中查询当前的要查询的接口。mybatis通生成缓存key来唯一判断当前的查询是否和之前的查询一致,一致则从缓存中取。(分析到这里我们可以发现mybatis会先查二级缓存,再查一级缓存)。
如果一级缓存查询为空,则调用queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql)方法。会把查询出来的结果放到一级缓存中。这里 boundSql是封装sql语句的详细信息,rowBounds是mybatis逻辑分页用的。parameter就是执行方法的参数。
进入doQuery方法,声明原生jdbc的Statement 对象。获取全局配置信息Configuration,new一个StatementHandler对,也就是mybatis的四大对象之一。
进去newStatementHandler方法,里面有interceptorChain.pluginAll(statementHandler)这是mybatis在生成四大对象通过拦截器链去获取代理对象,这边不详细解释。会有专门一章来讲。这里生成的对象是PreparedStatementHandler (默认情况)。
prepareStatement方法主要获取connection,也就是数据库连接对象。最终调用底层的数据查询,并将查询接口交给ResultSetHandler进行封装。
mybatis_运行原理_查询实现
最新推荐文章于 2023-02-22 16:26:09 发布