一分钟带你走进MyBatis的执行流程与底层解析

257 阅读3分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

  • 个人简介:微信公众号关注:SteveCode。为您分享更多的知识学术。生于忧患死于安乐
  • 专注Java技术干货分享,Java基础技术、数据结构、相关工具、Spring全家桶、intellij idea......

先看一段很熟悉的code,利用编程式进行数据查询

@Test
    void find() {
        SqlSession sqlSession = factory.openSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        List<User> all = mapper.findAll();
        log.info("find:{} ", all);
        
    }

获取Mapper接口(getMapper)

SqlSession对象是获取一个Mapper接口 在这里插入图片描述 在调用getMapper之后,会去Configuration对象中获取Mapper对象,因为在项目启动的时候就会把Mapper接口加载并解析存储到Configuration对象 在这里插入图片描述 通过Configuration对象中的MapperRegistry对象属性,继续调用getMapper方法 在这里插入图片描述 根据type类型,从MapperRegistry对象中的knownMappers获取到当前类型对应的代理工厂类,然后通过代理工厂类生成对应Mapper的代理类 在这里插入图片描述 最终获取到我们接口对应的代理类MapperProxy对象 在这里插入图片描述 在这里插入图片描述 结论:MapperProxy可以看到实现了InvocationHandler,使用的就是JDK动态代理。

问题来了mapper.xml文件时如何映射解析如何关联的呢??那些标签又是如何解析的?

第一个类开始说起:SqlSessionFactoryBuilder

在这里插入图片描述 首先我们会手动调用SqlSessionFactoryBuilder方法中的build()方法 在这里插入图片描述 然后会构造一个XMLConfigBuilder对象,并调用其parse方法: 在这里插入图片描述 继续调用自己的parseConfiguration来解析配置文件,这里面就会分别去解析全局配置文件的顶级节点。主要关注 mappers 在这里插入图片描述 面分了四种方式来解析mappers节点的配置,对应了4种mapper配置方式。MyBatis都会将xml映射文件和Mapper接口进行关联 在这里插入图片描述 说第二种 resource。会构建一个XMLMapperBuilder对象并调用其parse方法。 在这里插入图片描述 所有的:标签 都会被解析。 在这里插入图片描述 调用自身方法bindMapperForNamespace,开始绑定Mapper接口和映射文件: 在这里插入图片描述

在这里插入图片描述 调用Configuration对象的addMapper 在这里插入图片描述

在这里插入图片描述 调用Configuration对象的属性MapperRegistry内的addMapper方法,这个方法就是正式将Mapper接口添加到knownMappers,所以上面getMapper可以直接获取: 在这里插入图片描述 type:就是接口的绝对路径 **结论:**到这里我们就完成了Mapper接口和xml映射文件的绑定 parse方法,这个parse方法主要是解析注解 在这里插入图片描述 这个方法里面会去解析@Select等注解,需要注意的是,parse方法里面会同时再解析一次xml映射文件 在这里插入图片描述 同一个value会存储2次,一个全限定名作为key,另一个就是只用方法名(sql语句的id)来作为key 在这里插入图片描述 最终mappedStatements会是下面的情况: 在这里插入图片描述 事实上如果我们通过接口的方式来编程的话,最后来getStatement的时候,都是根据全限定名来取的,所以即使有重名对我们也没有影响,而之所以要这么做的原因其实还是为了兼容早期版本的用法

如何找到sql语句的?

介绍完了Mybatis执行流程 ,就是不知道 sql语句在哪执行的 我么往下看 先说结论:sql的执行 是交给了 代理对象 被代理对象的方法之后实际上执行的就是代理对象的invoke方法。因为我们这里并没有调用Object类中的方法,所以肯定走的else。 在这里插入图片描述

在这里插入图片描述 接下来,是构造一个MapperMethod对象,这个对象封装了Mapper接口中对应的方法信息以及对应的sql语句信息: 在这里插入图片描述

在这里插入图片描述

如何执行sql?

举个例子:就查询数据: 流程进入execute方法: 在这里插入图片描述 在这里插入图片描述 绕了这么一圈,回到了起点SqlSession对象,继续调用selectList方法: 在这里插入图片描述 委派给了Execute去执行query方法,最终又会去调用 在这里插入图片描述

在这里插入图片描述 在这里插入图片描述 do开头的方法就是真正做事的 在这里插入图片描述 在这里插入图片描述 继续进入PreparedStatementHandler对象的query方法,可以看到,这一步就是调用了jdbc操作对象PreparedStatement中的execute方法,最后一步就是转换结果集然后返回。 在这里插入图片描述 看源码我们也并不需要追求每一行代码都能看懂,然后如果对某些实现细节感兴趣,再深入进行了解。 在这里插入图片描述