Mybatis - 源码解析

入口

public static void statementTest() {
    // 1.0 配置解析入口
    // mybatis-config.xml - Configuration
    // mapper.xml - <Type,MapperProxyFactory>
    // mapper.xml#<select|insert|update|delete> - MappedStatement
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is,null,null);

    // 2.0 sqlSession获取(DefaultSqlSession 组合了一个 executor对象,具体的语句执行由executor对象完成)
    SqlSession sqlSession = sqlSessionFactory.openSession();
    try {
        // 3.0 获取代理对象
        KiqiMapper kiqiMapper = sqlSession.getMapper(KiqiMapper.class);

        // 4.0 通过代理对象实现sql语句的执行(代理对象方法 -> 触发管理类MapperProxy<T> -> mapperMethod.invoke()中根据statementId和sql类型调用sqlSession方法)
        Kiqi kiqi = kiqiMapper.selectByPrimaryKey(1);

        // 4.6 入口,4.0-4.5通过代理对象获取到相应的statementId和type类型,然后调用sqlSession方法
        Kiqi kiqi1 = sqlSession.selectOne(null,null);

        System.out.println(kiqi);
    } catch (Exception e){
        e.printStackTrace();
    } finally {
        sqlSession.close();
    }
}

配置读取 - SqlSessionFactoryBuilder().build();

① 读取mybatis-config.xml配置文件,构建configuration对象
② 读取Mapper.xml配置文件,创建Type-MapperProxyFactory<T>映射,MapperProxyFactory用于生成Mapper代理对象
③ 读取Mapper.xml - insert|update|delete|select标签,构建MappedStatement对象,用于语句执行
mybatis 会话工厂创建流程

创建会话 - sqlSessionFactory.openSqlSession();

  private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
    // 2.1 获取SqlSession
    Transaction tx = null;
    try {
      final Environment environment = configuration.getEnvironment();
      // 1. 获取事务工厂(事务工厂在config配置文件的environment标签中,通过配置文件设置 --- <transactionManager type="JDBC"/>)
      final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
      // 2. 创建事务对象
      tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
      // 3. 根据事务工厂和执行器配置,创建执行器
      final Executor executor = configuration.newExecutor(tx, execType);
      // 4. 创建DefaultSqlSession
      return new DefaultSqlSession(configuration, executor, autoCommit);
    } catch (Exception e) {
      closeTransaction(tx); // may have fetched a connection so lets call close()
      throw ExceptionFactory.wrapException("Error opening session.  Cause: " + e, e);
    } finally {
      ErrorContext.instance().reset();
    }
  }

获取mapper代理对象 - session.getMapper();

① 使用Type从configuration中获取到对应的MapperProxyFactory对象
② MapperProxyFactory创建MapperProxy对象(InvocationHandler接口实现类),并以此创建代理对象

  @SuppressWarnings("unchecked")
  public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
    // 3.2 在对mapper.xml文件解析时,构建了classType(namespace)与mapperProxyFactory的映射
    final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
    if (mapperProxyFactory == null) {
      throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
    }
    try {
      // 3.3 创建代理对象
      return mapperProxyFactory.newInstance(sqlSession);
    } catch (Exception e) {
      throw new BindingException("Error getting mapper instance. Cause: " + e, e);
    }
  }

public class MapperProxyFactory<T> {

  private final Class<T> mapperInterface;
  private final Map<Method, MapperMethodInvoker> methodCache = new ConcurrentHashMap<>();
  
  // ...

  @SuppressWarnings("unchecked")
  protected T newInstance(MapperProxy<T> mapperProxy) {
    // 1:类加载器、2:被代理类实现的接口、3:实现了 InvocationHandler 的触发管理类
    return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[]{mapperInterface}, mapperProxy);
  }

  public T newInstance(SqlSession sqlSession) {
    // 3.4 构建实现了 InvocationHandler接口的 触发管理类(特殊点:未封装被代理对象)
    final MapperProxy<T> mapperProxy = new MapperProxy<>(sqlSession, mapperInterface, methodCache);
    return newInstance(mapperProxy);
  }
}

执行mapper代理方法 - mapper.selectAll()

① 根据被调用的代理对象,调用对应的sqlSession方法 - eg: sqlSession.selectList(commandName,param);
调用代理对象方法 -> MapperProxy<T>.invoke()方法 -> MapperMethodInvoker.invoke()方法 -> mapperMethod.execute()方法 -> sqlSession方法

② sqlSession委托executor对象执行sql语句,先完成代理逻辑,再判断缓存是否存在,不存在则进入数据库查询逻辑
sqlSession.selectList() -> Executor.query() -> **intercept代理对象.intercept()** -> CachingExecutor代理对象查询二级缓存 -> baseExecutor查询一级缓存 -> 数据库查询

③ 数据库查询:BaseExecutor.queryFromDatabase() - 实质为对jdbc的封装

  1. 构建三大对象(StatementHandler,ParameterHandler 和 resultSetHandler)
  2. 从transaction对象中获取数据库链接connection
  3. 获取PrepareStatement对象
  4. 调用ParameterHandler.setParameters()方法,为pstm设置参数
  5. JDBC:pstm.execute(sql);
  6. resultSetHandler.handleResultSets(pstm),完成结果集处理
    Mybatis SQL调用执行流程
posted @ 2021-02-03 18:26  祁奇  阅读(86)  评论(0编辑  收藏  举报