1. Mybatis的架构概述
  2. 结合源码结构Mybatis的基本执行流程

一、Mybatis的架构概述

  1. Mybatis的架构概览如图所示:

2.第一层:SQLsession,直接对外暴露,也是我们最常用的组件:

<?xml version="1.0" encoding="UTF-8" ?>

<!DOCTYPE configuration

PUBLIC "-//mybatis.org//DTD Config 3.0//EN"

"http://mybatis.org/dtd/mybatis-3-config.dtd">

<configuration>

<!-- <properties resource="db.properties"></properties>-->

<environments default="development">

<environment id="development">

<transactionManager type="JDBC"></transactionManager>

<dataSource type="POOLED">

<property name="driver" value="com.mysql.jdbc.Driver"></property>

<property name="url" value="jdbc:mysql://localhost/mybatis_test"></property>

<property name="username" value="root"></property>

<property name="password" value="111111"></property>

</dataSource>

</environment>

</environments>

<!--加载映射文件-->

<mappers>

<mapper resource="cn/zephyr/mapper/SysUserMapper.xml"></mapper>

</mappers>

</configuration>

// 根据配置文件获取到SqlSessionFactory
 InputStream configFile = new FileInputStream("./src/main/resources/mybatis-conf.xml");
 // 根据SqlSessionFactory获取sqlSession
 SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(configFile);
 SqlSession sqlSession = sqlSessionFactory.openSession();
 // 在sqlSession中获取Mapper
 SysUserMapper mapper = sqlSession.getMapper(SysUserMapper.class);
 // 执行SQL查询,获取结果
 List<SysUser> sysUsers = mapper.queryList();
 System.err.println(Arrays.asList(sysUsers));

3.第二层:核心功能封装

  1. 配置parsing
  2. Parameter Mapping:查询条件的解析
  3. Sql Parsing:负责XxxMapper.xml或者基于注解(“@Select”等)的sql解析
  4. Executor:负责真正的SQL执行
  5. ResultSet Mapping:结果集映射
  6. Plugins:提供插件支持

4.第三层:最底层的功能

  1. 数据源:提供数据源支持
  2. 缓存:提供缓存支持
  3. Binding:负责将XxxMapper.java与XxxMapper.xml做双向绑定
  4. 日志:日志输出sql语句的执行日志,内部使用了代理模式,此处略加说明

1.抽象类是BaseJdbcLogger,同级包下有4个子类进行集成

2.以ConnectionLogger为例,各个Executor在执行sql之前获取到的connection,其实是connection的代理对象,通过代理类实现建立连接时的日志打印:

3.再通过配置项,实现对打印日志的开关控制:

4.资源加载

5.类型转换:负责将Java的数据类型与SQL的数据类型之间的互相转换

6.事务管理:Mybatis提供了轻量级的事务管理(很少用,实际项目使用时,通常将Mybatis集成到Spring,这种情况下,事务将由spring统一管理)

7.反射:封装了Java的反射方法作为工具类,起到了简化代码的作用

8.parsing:负责XxxMapper.xml或者基于注解(“@Select”等)的sql解析(以面向对象的思想来看待mybatis,XxxMapper.java是一个动作,对应的结果实体对应到实际的数据库表是一个名词)

二、结合源码结构Mybatis的基本执行流程

1. 先说结论

  1. 再贴一下原生使用mybatis的示例代码(为了简单,只使用了一个xml配置文件,相关的Java代码都写在单元测试用,pom直接使用了mybatis.springboot.starter):
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
 PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
 "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!-- <properties resource="db.properties"></properties>-->
 <environments default="development">
 <environment id="development">
 <transactionManager type="JDBC"></transactionManager>
 <dataSource type="POOLED">
 <property name="driver" value="com.mysql.jdbc.Driver"></property>
 <property name="url" value="jdbc:mysql://localhost/mybatis_test"></property>
 <property name="username" value="root"></property>
 <property name="password" value="111111"></property>
 </dataSource>
 </environment>
 </environments>
 <!--加载映射文件-->
 <mappers>
 <mapper resource="cn/zephyr/mapper/SysUserMapper.xml"></mapper>
 </mappers>
</configuration>
// 1. 读取配置文件
 InputStream configFile = new FileInputStream("./src/main/resources/mybatis-conf.xml");
 // 2. 根据配置文件获取到SqlSessionFactory
 SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(configFile);
 // 3. 根据SqlSessionFactory获取sqlSession
 SqlSession sqlSession = sqlSessionFactory.openSession();
 // 4. 在sqlSession中获取Mapper
 SysUserMapper mapper = sqlSession.getMapper(SysUserMapper.class);
 // 5. 执行SQL查询,获取结果
 List<SysUser> sysUsers = mapper.queryList();
 System.err.println(Arrays.asList(sysUsers));

2.结论:

<mappers>

2. 结论验证:

  1. 第一步:加载配置文件到IO流;
InputStream configFile = new FileInputStream("./src/main/resources/mybatis-conf.xml");
复制代码

2.第二步:解析配置文件;

SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(configFile);
复制代码
  1. 这一步主要做的事情就是根据配置文件获取所有的Mapper.xml,从而获取Mapper接口类,并以Mapper接口类为键,对应的代理工厂对象为值,存储到一个Mapper容器(knownMappers)中。这一步整体的代码执行流程如下图所示:

3.第三步:获取sqlSession(此处暂不展开分析);

SqlSession sqlSession = sqlSessionFactory.openSession();

4.第四步:根据Mapper接口类获取实现类(动态代理生成的对象);

sqlSession.getMapper(SysUserMapper.class);

这一步就根据接口类,从之前的容器(knownMappers)中拿到对应的代理工厂对象,生成对应的代理对象并将其返回,这一步整体的代码执行流程如下:

通过断点可以看到,最终拿到的对象实现类对象是一个代理对象

5.第五步:调用Executor执行sql

List<SysUser> sysUsers = mapper.queryList();