MyBatis 的秘密(五)整体流程图

执行流程图

通过前面的分析,我们梳理了MyBatis从调用方法到返回结果的整个流程,这里我们简单的做一个总结:

image

先上图,按道理来说时序图应该是最合适的,但是我觉得上面的文字过多。接下来结合上面的图详细说说MyBatis从启动到返回结果的流程。

  • 首先,使用SqlSessionFactoryBuilder读取MyBatisXML配置文件,并解析配置,生成Configuration对象,返回SqlSessionFactory

    调用build方法可以传递Environment选择使用的环境

    同时可以执行Properties,并且此Properties的优先级最高


  • 通过SqlSessionFactory可以获取SqlSession,SqlSessionFactory的作用如其名字所示,根据不同参数产生SqlSession

    同理,通过SqlSessionFactory获取SqlSession的时候,也可以传递一下参数:

    • ExecutorType : 选择使用的Executor , 默认为SIMPLE
    • AutoCommit : 是否开启事务

    还有其他的比如事务级别等

    注意: 虽然这里可以指定是否开启事务,但是具体真的是否开启事务,还是由实现了MyBatisTransaction接口的事务管理器处理,不一定是真正的开启了事务


  • 获取到SqlSession后,便可以调用想要执行的MapperSqlSession对应的方法被调用后,会简单的处理参数,将参数装化为Executor需要的类型

    对于Executor来说,SQL就分两种,即查找(query())和修改(update()) ,我们使用的SqlSession中个中方法,最终都会被转换为这两种形式,然后调用Executor

    当使用Select的时候,可以传递一个ResultHanlder,自行处理结果


  • Executor被调用后,会根据所配置的Statement,创建不同的StatmentHandler,然后将SQL交给StatmentHandler处理

    ExecutorMyBatis中有4种实现,其中可以配置的分别是SIMPLE,REUSE,BATCH ,默认为SIMPLE,其中REUSE会缓存创建的StatmentHandler,BATCH底层调用的是JDBC#batch()方法

    另外一种是其他Executor的包装类:CachingExecutor,当开启了二级缓存的时候,默认会先使用CachingExecutor进行查找,当无法查找成功的时候,再委托给后面3种Executor进行查找

    StatementHandlerMyBatis中有3种实现,可以配置的是PREPARED , STATEMENT,CALLABLE ,分别对应JDBC中的PreparedStatmentStatement , CallableStatment

    通过这一步,Executor会初始化StatmentHandler所有参数,比如参数(通过TypeHandler设置),超时时间,FetchSize


  • StatementHandler被调用后,就会真正的执行SQL,在执行完毕后,对于update(),则直接返回被影响的行数,如果需要返回自增长id,则使用KeyGenerator查询Id,对于查询select(),则会交由ResultSetHandler逐行处理数据

    StatementHandler所做的工作并不多,底层便是调用的真正的JDBCStatement工作,然后根据所执行的操作的不同,对结果进行不同的处理


  • 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却真正的体现出了面向对象的单一职责原则,依赖注入原则,从而基本能够做到开闭原则。