执行流程图
通过前面的分析,我们梳理了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
却真正的体现出了面向对象的单一职责原则,依赖注入原则,从而基本能够做到开闭原则。