通过前面的分析,我们梳理了 MyBatis
从调用方法到返回结果的整个流程,这里我们简单的做一个总结:
先上图,按道理来说时序图应该是最合适的,但是我觉得上面的文字过多。接下来结合上面的图详细说说 MyBatis
从启动到返回结果的流程。
SqlSessionFactoryBuilder
读取 MyBatis
的 XML
配置文件,并解析配置,生成 Configuration
对象,返回 SqlSessionFactory
调用 build
方法可以传递 Environment
选择使用的环境
同时可以执行 Properties
,并且此 Properties
的优先级最高
SqlSessionFactory
可以获取 SqlSession
, SqlSessionFactory
的作用如其名字所示,根据不同参数产生 SqlSession
同理,通过 SqlSessionFactory
获取 SqlSession
的时候,也可以传递一下参数:
ExecutorType
: 选择使用的 Executor
, 默认为 SIMPLE
AutoCommit
: 是否开启事务 还有其他的比如事务级别等
注意:虽然这里可以指定是否开启事务,但是具体真的是否开启事务,还是由实现了 MyBatis
的 Transaction
接口的事务管理器处理,不一定是真正的开启了事务
获取到 SqlSession
后,便可以调用想要执行的 Mapper
, SqlSession
对应的方法被调用后,会简单的处理参数,将参数装化为 Executor
需要的类型
对于 Executor
来说, SQL
就分两种,即查找( query()
)和修改( update()
) ,我们使用的 SqlSession
中个中方法,最终都会被转换为这两种形式,然后调用 Executor
当使用 Select
的时候,可以传递一个 ResultHanlder
,自行处理结果
Executor
被调用后,会根据所配置的 Statement
,创建不同的 StatmentHandler
,然后将 SQL
交给 StatmentHandler
处理
Executor
在 MyBatis
中有4种实现,其中可以配置的分别是 SIMPLE
, REUSE
, BATCH
,默认为 SIMPLE
,其中 REUSE
会缓存创建的 StatmentHandler
, BATCH
底层调用的是 JDBC#batch()
方法
另外一种是其他 Executor
的包装类: CachingExecutor
,当开启了二级缓存的时候,默认会先使用 CachingExecutor
进行查找,当无法查找成功的时候,再委托给后面3种 Executor
进行查找
StatementHandler
在 MyBatis
中有3种实现,可以配置的是 PREPARED
, STATEMENT
, CALLABLE
,分别对应 JDBC
中的 PreparedStatment
, Statement
, CallableStatment
通过这一步, Executor
会初始化 StatmentHandler
所有参数,比如参数(通过 TypeHandler
设置),超时时间, FetchSize
等
StatementHandler
被调用后,就会真正的执行 SQL
,在执行完毕后,对于 update()
,则直接返回被影响的行数,如果需要返回自增长 id
,则使用 KeyGenerator
查询 Id
,对于查询 select()
,则会交由 ResultSetHandler
逐行处理数据
StatementHandler
所做的工作并不多,底层便是调用的真正的 JDBC
的 Statement
工作,然后根据所执行的操作的不同,对结果进行不同的处理
当 StatmentHandler
获取到查询结果后,会调用 ResultSetHandler
处理结果, ResultSetHandler
会根据 XML
中所配置的方法进行结果处理,如果没有嵌套结果,则进行简单处理,如果还有动态嵌套,并且 设置了延迟加载 ,那么 ResultSetHandler
会通过 CGLIB
(默认)或则 javassist
框架生成一个代理对象,当真正调用此方法的时候再去查询.
ResultSetHandler
处理结果输入为 Statement
,输出为真正的结果,当 ResultSetHandler
获取到 Statement
的时候, Statement
已经执行了 execute()
方法,之所以说这么多,是因为后面的插件( Plugin
) 会使用到
ResultSetHandler
在处理每一行数据的时候,都是通过调用 TypeHandler
加上反射完成 ORM
,当成功生成对象后再调用的 ResultHandler
进行额外的处理,不过默认的 DefaultResultHandler
并没有进行什么特殊的处理,
MyBatis
允许我们自定义 ResultHandler
处理结果,不过限制为方法返回为 void
以上,便是 MyBatis
的整体调用流程,可以看出来算是 MyBatis
的代码分层分的非常细。以上这些逻辑代码,其实在一个类中都能完成。不过那样显得十分臃肿,而 MyBatis
却真正的体现出了面向对象的单一职责原则,依赖注入原则,从而基本能够做到开闭原则。