首先是环境准备,SqlSessionFactory初始化时会解析xml配置文件,解析为Environment、Configuration对象
通过SqlSessionFactory获取一个SqlSession
SqlSession中包含一个执行器Executor以及配置类实例:Configuration对象,主要用于sql的执行,是mybatis的核心组件。
随后通过SqlSession我们可以拿到Mapper的代理对象,代理对象在创建过程中需要我们定义的mapper接口
通过代理工厂完成代理类的实例化。
因为是在接口的基础上生成代理对象的,所以直接用了jdk代理。
获取到代理对象后,就可以传入参数执行sql了。
随后进入代理对象的invoke方法,在代理对象中过滤了Object中的方法(并不是所有方法都需要代理)。
通过MapperMethod执行sql
上图可以看出mybatis对MapperMethod做了一个缓存,缓存的数据结构为map,key值为mapper方法的全路径。
MapperMethod其实可以看成是一个sql骨架,我们只需要给他填充基本的参数,就可以执行对应的sql。
从缓存中取出MapperMethod后,开始执行sql
执行时会根据sql的类型做一个区分
根据返回值的多少,做区分处理,比如我当前执行的查询语句返回值是一个Role对象,那么最终会调用sqlSession的selectOne
注意,此时参数已经被处理过了
即使是selectOne,mybatis也会交给selectList处理,但如果返回值不是一个或者0个时,会抛出对应的异常。这个异常并非jdbc抛出,而是mybatis自己抛出。
通过statement拿到关键的MappedStatement。
这里有两个比较关键的地方。
1、statement是什么?
针对我此时执行的sql,statement是“customer.mapper.RoleMapper.getRole“
其实就是mapper接口中getRole方法的全路径。
这个全路径是不带参数的,作为map的key值,所以在写mapper接口时,不支持重载。
2、MappedStatement是什么?
这个之前的博客已经研究过了,比如说现在用的是xml,MappedStatement就是对xml的一个抽象,比如有参数映射、结果集映射、主键生成规则等
回到主线
调用executor的query方法执行最后的sql查询
创建一个BoundSql对象
此时的sql还未替换参数
最后开始从数据库中查询数据,这里对查询结果也做了一个缓存,也就是说在参数相同时,连续的查询可能不会每次都去数据库查。
继续向后走,跳过两个步骤后到如下方法
此时已经拿到了Connection对象,并且开始参数赋值了。
以前用原生jdbc时,对预编译的sql设置参数时,通常会用到setInt,setString之类的函数。
mybatis在设置参数时会调用对应的映射器,将Java中的type转变为sql中的type
拿到了最终要执行的sql
这里的preparedStatement是已经赋值成功后的preparedStatement
执行后结果交给ResultSetHandler来处理,其实就是将结果集解析式对应的Java对象的过程。
最后跳转到我们自己的程序,拿到最终的结果。
如有错误,欢迎批准指正。