MyBatis执行sql的整个流程

大致过程:启动->解析配置文件->创建executor->绑定参数->执行sql->结果集映射

扫描配置

@MapperScan,配置了@Import(MapperScannerRegistrar.class)。MapperScannerRegistrar 用于注册 MapperScannerConfigurer BeanDefinition。

MapperScannerConfigurer 主要实现了 BeanDefinitionRegistryPostProcessor 接口。
其 postProcessBeanDefinitionRegistry 方法,通过 ClassPathMapperScanner 将扫描的信息转化为 MapperFactoryBean BeanDefinition。

获取代理对象及调用具体过程

1、Mapper 的获取:

  • 创建sqlSessionFactory对象
  • SqlSessionFactoryBuilder 创建Configuration对象,然后根据Configuration对象创建SqlSessionFactory。Configuration =>(作为构造器参数)=> 返回 DefaultSqlSessionFactory。
  • mybatis-spring,由 SqlSessionFactoryBean 创建 SqlSessionFactory。
  • mybatis-plus,MybatisPlusAutoConfiguration 中由 MybatisSqlSessionFactoryBean 创建 SqlSessionFactory。
  • 创建sqlSession对象
  • SqlSessionFactory 创建SqlSession对象。
  • => DefaultSqlSessionFactory.openSession => openSessionFromDataSource =>
    先创建Executor,再根据 Configuration、Executor(默认使用SimpleExecutor)、autoCommit 返回 DefaultSqlSession。
  • mybatis-spring、mybatis-plus中类型为:SqlSessionTemplate。
  • 获取Mapper接口的代理对象
  • Configuration、mybatis-spring
  • => 调用 SqlSession 接口的 <T> T getMapper(Class<T> type)
  • => 调用Configuration实例的 <T> T getMapper(Class<T> type, SqlSession sqlSession)
  • => 调用MapperRegistry实例的 <T> T getMapper(Class<T> type, SqlSession sqlSession)
  • => 在 MapperRegistry 中根据已注册的 MapperProxyFactory 返回mapperProxyFactory.newInstance(sqlSession) 的结果——代理对象
  • mybatis-plus,同上,但使用的是 MybatisConfiguration、MybatisMapperRegistry。
MapperRegistry、MapperProxyFactory<T>、MapperProxy<T>的联系

MapperRegistry 用来缓存 MapperProxyFactory,并根据它和SqlSession来生成Mapper对象。
以下是它的两个属性:

private final Configuration config;
private final Map<Class<?>, MapperProxyFactory<?>> knownMappers = new HashMap<>();
  • knownMappers
  • key 是Mapper类。
  • value 是生成Mapper代理的工厂类。

MapperProxyFactory 使用MapperProxy生成 Mapper 代理对象。两个属性:

private final Class<T> mapperInterface;
private final Map<Method, MapperMethodInvoker> methodCache = new ConcurrentHashMap<>();
  • mapperInterface:mapper 接口。
  • methodCache:初始时大小为0,后续调用到 MapperProxy 时,添加(如果缓存中没有)。
  • key 为 mapper 接口中定义的方法。
  • value 类型为MapperMethodInvoker,是 MapperProxy 中定义的接口,类似于 InvocationHandler。

MapperProxy

  • 相比 MapperProxyFactory,MapperProxy 多了一个SqlSession属性。
  • MapperProxy 实现了 InvocationHandler,用于生成Mapper代理对象,即调用Mapper接口中的方法,会调用MapperProxy中实现的 invoke 方法。
  • MapperProxy中 的 invoke 调用的是 MapperMethod 的 execute 方法。
@Override
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    try {
      if (Object.class.equals(method.getDeclaringClass())) {
        return method.invoke(this, args);
      } else {
        return cachedInvoker(method).invoke(proxy, method, args, sqlSession);
      }
    } catch (Throwable t) {
      throw ExceptionUtil.unwrapThrowable(t);
    }
  }
  
  private MapperMethodInvoker cachedInvoker(Method method) throws Throwable {
    try {
      return MapUtil.computeIfAbsent(methodCache, method, m -> {
        if (m.isDefault()) { //如果是 default 方法
          try {
            if (privateLookupInMethod == null) {
              return new DefaultMethodInvoker(getMethodHandleJava8(method));
            } else {
              return new DefaultMethodInvoker(getMethodHandleJava9(method));
            }
          } catch (IllegalAccessException | InstantiationException | InvocationTargetException
              | NoSuchMethodException e) {
            throw new RuntimeException(e);
          }
        } else {
          return new PlainMethodInvoker(new MapperMethod(mapperInterface, method, sqlSession.getConfiguration()));
        }-
      });
    } catch (RuntimeException re) {
      Throwable cause = re.getCause();
      throw cause == null ? re : cause;
    }
  }

2、Mapper 中方法的调用:

  • 调用 Mapper 中的方法
  • => MapperProxy.invoke = > MapperMethod.execute
  • => 调用 sqlSession.selectXXX 方法,即:SqlSessionTemplate => DefaultSqlSession
  • 使用 Executor
  • Executor(由Configuration.newExecutor创建;实现之一的CachingExecutor是包装类,包含属性 Executor delegate,启用缓存则进行包装)
  • 执行 SimpleExecutor的方法(默认的Executor,调用StatementHandler,实现方法:doQuery、doUpdate、doQueryCursor):
  • 生成StatementHandler代理对象(由Configuration.newStatementHandler创建,处理SQL语句,预编译,设置参数)
  • 使用 StatementHandler 创建 Statement 并执行
  • BaseStatementHandler 构造器中设置了 ParameterHandler、ResultSetHandler 两个实例。由Configuration中的两个方法创建:Configuration.newParameterHandler、Configuration.newResultSetHandler。
  • 调用 prepare 方法创建 Statement
  • 调用 parameterize 方法设置参数 => 调用ParameterHandler设置参数(设置编译参数,设置参数:CallableStatementHandler、PreparedStatementHandler 中调用)
  • 调用 query 方法 => 调用ResultSetHandler处理结果(处理查询结果,有三个方法)
  • 备注
  • TypeHandler(数据库类型和JavaBean类型映射处理)
  • JDBCStatement.PreparedStatement(最终用原生JDBC的API处理)