Mybatis源码全流程切割分析

1. Mybatis

本文mybatis源码的分析大致思路围绕着下列代码进行开展的,如下4段代码。

//获取SqlSession工厂
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("Mybatis-Config.xml"));
//工厂生成一个SqlSession会话
SqlSession session = factory.openSession(true);
//获取一个代理对象
UserMapper mapper = session.getMapper(UserMapper.class);
//执行sql语句并映射结果集
User user = mapper.selectById(42);

2. SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream(“Mybatis-Config.xml”));

 public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
    try {
    /**
    	inputStream表示字节输入流的类的超类,通过它来读取xml文件,Resources.getResourceAsStream("Mybatis-Config.xml")
    	最终返回的是一个BufferedInputStream字节输入流对象,因为无论是类还是xml文件等,都需要被classLoader装载到内存后才能被当前线程使用,
   		而Mybatis-Config.xml文件其实是被AppClassLoader下的getResourceAsStream方法装载到内存的,
   		(根据双亲委派原则,AppClassLoader负责加载类路径下的指定内容)
   		此时的inputStream对象中的数据是字节序列,需要被解析转化
   		environment和properties此时为均为空对象,将引用传递new XMLConfigBuilder(inputStream, environment, properties);
   		由于是单例对象引用传递,该构造方法执行结束后,environment和properties均有值
   	**/
      XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
  
      return build(parser.parse());
    } catch (Exception e) {
      throw ExceptionFactory.wrapException("Error building SqlSession.", e);
    } finally {
      ErrorContext.instance().reset();
      try {
        inputStream.close();
      } catch (IOException e) {
        // Intentionally ignore. Prefer previous error.
      }
    }
  }

XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties)的详细如下:

public XMLConfigBuilder(InputStream inputStream, String environment, Properties props) {
	//注:这里new XPathParser(inputStream, true, props, new XMLMapperEntityResolver())
	//将inputStream的字节序列数据转换为document节点树对象
    this(new XPathParser(inputStream, true, props, new XMLMapperEntityResolver()), environment, props);
  }

 private XMLConfigBuilder(XPathParser parser, String environment, Properties props) {
 //初始化一个Configuration对象,成员变量均为初始值
    super(new Configuration());
    ErrorContext.instance().resource("SQL Mapper Configuration");
    this.configuration.setVariables(props);
    this.parsed = false;
    this.environment = environment;
    this.parser = parser;
  }

补充XPathParser:

 public XPathParser(InputStream inputStream, boolean validation, Properties variables, EntityResolver entityResolver) {
    commonConstructor(validation, variables, entityResolver);
	//XMLInputSource读取字节数组中的数据,最终将其转换为Document节点树对象
	//Document对象是org.w3c.dom包下的,Document接口代表整个 HTML 或 XML 文档。 从概念上讲,它是文档树的根,并提供对文档数据的主要访问。。
    this.document = createDocument(new InputSource(inputStream));
  }

super(new Configuration())

  public BaseBuilder(Configuration configuration) {
    this.configuration = configuration;
    //别名注册实例化
    this.typeAliasRegistry = this.configuration.getTypeAliasRegistry();
    //类型转化注册器实例化,当数据库映射字段类型和实体类属性类型不一致时,则通过该类型转换器将映射字段类型处理为实体类属性字段
    this.typeHandlerRegistry = this.configuration.getTypeHandlerRegistry();
  }

XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);执行结束后, XMLConfigBuilder对象具有主要的成员遍历有:实例化完成的Configuration配置对象,此时并未初始化完成,TypeAliasRegistr别名注册器,TypeHandlerRegistry做类型处理注册

  public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
    try {
      XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
      return build(parser.parse());
      ....省略以下代码
      build(parser.parse());
     			|
XMLConfigBuilder:    
public Configuration parse() {
    if (parsed) {
      throw new BuilderException("Each XMLConfigBuilder can only be used once.");
    }
    parsed = true;
    //该方法用于初始化Configuration配置类对象
    //parser.evalNode("/configuration")解析document对象为XNode对象(该对象是Mybatis自定义的对象,用于存储document中的Node节点)
    parseConfiguration(parser.evalNode("/configuration"));
    //此时的configuration初始化完成,返回
    return configuration;
  }

补充: parseConfiguration(parser.evalNode("/configuration"));

private void parseConfiguration(XNode root) {
    try {
      //这些字段均为Mybatis配置文件中可配置的标签
      propertiesElement(root.evalNode("properties"));
      Properties settings = settingsAsProperties(root.evalNode("settings"));
      loadCustomVfs(settings);
      typeAliasesElement(root.evalNode("typeAliases"));
      pluginElement(root.evalNode("plugins"));
      objectFactoryElement(root.evalNode("objectFactory"));
      objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
      reflectorFactoryElement(root.evalNode("reflectorFactory"));
      settingsElement(settings);
      // read it after objectFactory and objectWrapperFactory issue #631
      environmentsElement(root.evalNode("environments"));
      databaseIdProviderElement(root.evalNode("databaseIdProvider"));
      typeHandlerElement(root.evalNode("typeHandlers"));
      mapperElement(root.evalNode("mappers"));
    } catch (Exception e) {
      throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
    }
  }

执行结束后返回一个SqlSessionFactory对象

  public SqlSessionFactory build(Configuration config) {
    return new DefaultSqlSessionFactory(config);
  }

总结:SqlSessionFactoryBuilder()通过读取配置文件转为InputStream对象,再读取该对象转换为Document节点对象,将该对象封装在XPathParser(Mybatis自定义)中,再调用XPathParser的evalNode读取对应的Node节点。再将该节点封装再XNode对象。
为啥这样呢?因为方便接下来build构造SqlSessionFactory更加便捷,通过指定字段读取XNode的指定节点对象,让其封装在特点对象中,如配置文件中的environment标签封装在environment对象中,mappers标签下配置的类路径会使用类加载器加载到内存等待读取,如配置了package name=“com.hnjd.mapper”/ 会去扫描mapper下的接口将其封装在MapperRegistry对象中,内有一个成员变量knownMappers,HashMap的结构,key值为接口的类信息,value值为一个代理对象MapperProxyFactory工厂对象,该对象中封装了相应的Class对象,最终返回一个MapperProxy代理对象,这就是为啥我们可以通过 UserMapper mapper = session.getMapper(UserMapper.class);获取到相应的UserMapper代理对象,就是去MapperRegistry对象中读取的。
最终像environment对象,以及MapperRegistry对象和配置文件中的标签转化的对象,都存放在Configuration对象中,类似在配置文件中configuration是environment和mappers的根标签一样,而Configuration配置类对象又存储在SqlSessionFactory中。
最后可以分析得出:SqlSessionFactory有两件事:1.存放Configuration配置类,2.根据Configuration配置类生产相应的SqlSession。

补充MapperRegister:
在这里插入图片描述

3.SqlSession session = factory.openSession(true);

org.apache.ibatis.session.defaults.DefaultSqlSessionFactory
 @Override
  public SqlSession openSession(boolean autoCommit) {
    return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, autoCommit);
  }
			
		
//configuration.getDefaultExecutorType()获取默认的执行器
//Configuration中默认的执行器为SIMPLE
//可以通过	<setting name="defaultExecutorType" value="BATCH"/>配置
// protected ExecutorType defaultExecutorType = ExecutorType.SIMPLE;
//而执行器类型分三种,是枚举的形式(看Mybatis版本所示)
package org.apache.ibatis.session;
public enum ExecutorType {
//策略模式,三种策略
  SIMPLE, REUSE, BATCH
}
//根据Mybatis官方文档所述
SIMPLE:普通的执行器
REUSE:重用预处理语句(PreparedStatement)
BATCH:不仅重用语句还会执行批量更新

生产SqlSession的过程如下所示

 private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
    Transaction tx = null;
    try {
    	//获取 Environment,用于连接数据库,Mybatis底层操作MySQL数据库的方式仍然是JDBC,只不过对结果集映射的处理更加只能了,还有各种拦截器的配合使用,同时可以利用拦截器生成日志了
      final Environment environment = configuration.getEnvironment();
      //获取事务工厂,为JdbcTransactionFactory,根据Connection用于生产JdbcTransaction
      final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
      //JdbcTransaction的事务控制就是封装了下Connection的commit和rollback,当openSession(true)指定为true了,就是使用JdbcTransaction做事务控制,
      tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
      //根据事务和执行器类型生成Executor,Mybaits是使用Executor执行SQL语句所以需要事务transaction对象。
      final Executor executor = configuration.newExecutor(tx, execType);
      //根据Configuration配置类和Executor执行器生成SqlSession对象,以及autoCommit是否由Mybaits管理事务
      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();
    }
  }

补充: final Executor executor = configuration.newExecutor(tx, execType);执行器的实例化过程

org.apache.ibatis.session.Configuration

public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
//根据执行器类型生成相应的执行器
    executorType = executorType == null ? defaultExecutorType : executorType;
    executorType = executorType == null ? ExecutorType.SIMPLE : executorType;
    Executor executor;
    if (ExecutorType.BATCH == executorType) {
     //Batch类型
      executor = new BatchExecutor(this, transaction);
    } else if (ExecutorType.REUSE == executorType) {
      //REUSE类型
      executor = new ReuseExecutor(this, transaction);
    } else {
      //SIMPLE类型
      executor = new SimpleExecutor(this, transaction);
    }
    if (cacheEnabled) {
    //!无论是那种类型这里都会将其封装到CachingExecutor执行器中,也就是说当调用执行器的方法,会调用CachingExecutor再调用相应类型执行器的方法
      executor = new CachingExecutor(executor);
    }
    //将执行器进行动态代理
    executor = (Executor) interceptorChain.pluginAll(executor);
    return executor;
  }
	
//补充  executor = (Executor) interceptorChain.pluginAll(executor);
org.apache.ibatis.plugin.InterceptorChain

public class InterceptorChain {

  private final List<Interceptor> interceptors = new ArrayList<Interceptor>();

  public Object pluginAll(Object target) {
  //如果配置了拦截器则调用拦截器内部的plugin方法,plugin会调用Plugin类的warp方法进行动态代理,传入的target方法正是执行器对象
    for (Interceptor interceptor : interceptors) {
    //循环目的,配置了多少个拦截器就代理几次,类似套娃
      target = interceptor.plugin(target);
    }
    return target;
  }

  public void addInterceptor(Interceptor interceptor) {
    interceptors.add(interceptor);
  }
  
  public List<Interceptor> getInterceptors() {
    return Collections.unmodifiableList(interceptors);
  }

}
.
//补充org.apache.ibatis.plugin.Plugin 
//targetCachingExecutor执行器对象
  public static Object wrap(Object target, Interceptor interceptor) {
    Map<Class<?>, Set<Method>> signatureMap = getSignatureMap(interceptor);
    Class<?> type = target.getClass();
    Class<?>[] interfaces = getAllInterfaces(type, signatureMap);
    if (interfaces.length > 0) {
    //返回代理对象
      return Proxy.newProxyInstance(
          type.getClassLoader(),
          interfaces,
          new Plugin(target, interceptor, signatureMap));
    }
    return target;
  }

总结:获取SqlSession的过程就是,从factory工厂拿出Configuration配置类,从Configuration拿出Environment生成Transaction事务管理,Trasaction事务对象生成后,根据Tracation和执行器类型生成Executor执行器,最后将Configuration和Execturo执行器和标识事务管理传入SqlSession中返回。
最后分析得出:SqlSession就是根据Executuro执行器和Configuration配置类生成的,而执行器就是根据Trasaction事务管理器生成的,而SqlSesion的作用由于有执行器则可以执行语句,由于有Trasaction则可以管理事务,以及获取映射器(请继续见本文分析)

4.UserMapper mapper = session.getMapper(UserMapper.class);

  org.apache.ibatis.session.defaults.DefaultSqlSession
  
  @Override
  public <T> T getMapper(Class<T> type) {
    return configuration.<T>getMapper(type, this);
  }
 
  org.apache.ibatis.session.Configuration
  public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
  //这就是加载Configuration通过读取配置文件中Mappers节点封装生成的MapperRegistry
    return mapperRegistry.getMapper(type, sqlSession);
  }
	
  org.apache.ibatis.binding.MapperRegistry

  public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
  	//key值为接口的类信息,value值为一个代理对象MapperProxyFactory工厂对象,该对象中封装了相应的Class对象,最终返回一个MapperProxy代理对象
    //private final Map<Class<?>, MapperProxyFactory<?>> knownMappers = new HashMap<Class<?>, MapperProxyFactory<?>>();
    //根据Class类信息获取生成代理对象的工厂MapperProxyFactroy
    final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
    if (mapperProxyFactory == null) {
    	//如果该Class对象并没有在MapperRegistry中注册,或者说是没有在配置文件Mappers中配置,报出该类型并没有被注册的异常信息
      throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
    }
    try {
     //根据sqlSession通过工厂实例化一个代理对象
      return mapperProxyFactory.newInstance(sqlSession);
    } catch (Exception e) {
      throw new BindingException("Error getting mapper instance. Cause: " + e, e);
    }
  } 
 
  org.apache.ibatis.binding.MapperProxyFactory<T>
  public T newInstance(SqlSession sqlSession) {
  	//根据sqlSession和类信息生成一个MapperProxy对象
    final MapperProxy<T> mapperProxy = new MapperProxy<T>(sqlSession, mapperInterface, methodCache);
    return newInstance(mapperProxy);
  }

	protected T newInstance(MapperProxy<T> mapperProxy) {
    	//调用JDK的代码生成代理对象
    	return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
  }

总结:通过class类信息getMapper的过程就是去Configuration中的MapperRegistry中的Class类信息和MapperProxyFactory工厂的Map对象中根据Class类信息get相应的MapperProxy工厂实例化生成MapperProxy代理对象

5.User user = mapper.selectById(42);

该mapper对象是一个MapperProxy代理对象,请看MapperProxy代理对象中的invoke方法

@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 if (isDefaultMethod(method)) {
        return invokeDefaultMethod(proxy, method, args);
      }
    } catch (Throwable t) {
      throw ExceptionUtil.unwrapThrowable(t);
    }
    //重点在这,上述只是特殊情况的判断
    //将Method对象放进methodCache缓存中
    final MapperMethod mapperMethod = cachedMapperMethod(method);
    //传入SqlSession(因为内部封装了执行器,sql语句的执行需要它),args就是方法参数调用execute
    return mapperMethod.execute(sqlSession, args);
  }
 //补充:
	private MapperMethod cachedMapperMethod(Method method) {
	//private final Map<Method, MapperMethod> methodCache;
		//当方法重复调用时,优先取缓存中取
    	MapperMethod mapperMethod = methodCache.get(method);
    	if (mapperMethod == null) {
    	//当方法初次调用时,生成MapperMethod对象放进缓存中,该对象中主要是SqlCommand(封装了类路径和Sql语句的类型,如本文是“SELECT”,策略模式,详细了解请继续看下文所述)和MethodSignature方法签名(判断返回值类型)两个成员变量
     	 mapperMethod = new MapperMethod(mapperInterface, method, 	sqlSession.getConfiguration());
      	methodCache.put(method, mapperMethod);
    	}
    	return mapperMethod;
  }

mapperMethod.execute(sqlSession, args)

 org.apache.ibatis.binding.MapperMethod
   public Object execute(SqlSession sqlSession, Object[] args) {
    Object result;
    switch (command.getType()) {
    //步骤4.在MapperMethod的SqlCommand中封装的SQL语句类型在这里起作用了,策略模式,本文为查询SELECTE,所以直接看SELECTE
      case INSERT: {
    	Object param = method.convertArgsToSqlCommandParam(args);
        result = rowCountResult(sqlSession.insert(command.getName(), param));
        break;
      }
      case UPDATE: {
        Object param = method.convertArgsToSqlCommandParam(args);
        result = rowCountResult(sqlSession.update(command.getName(), param));
        break;
      }
      case DELETE: {
        Object param = method.convertArgsToSqlCommandParam(args);
        result = rowCountResult(sqlSession.delete(command.getName(), param));
        break;
      }
      case SELECT:
      //这里条件判断就是根据MapperProxy执行方法后的返回值是什么类型判断的,method为MethodSignature
        if (method.returnsVoid() && method.hasResultHandler()) {
        //无返回值
          executeWithResultHandler(sqlSession, args);
          result = null;
        } else if (method.returnsMany()) {
          //返回的是集合等类型的
          result = executeForMany(sqlSession, args);
        } else if (method.returnsMap()) {
          //返回的是Map类型的
          result = executeForMap(sqlSession, args);
        } else if (method.returnsCursor()) {
          //流式查询
          result = executeForCursor(sqlSession, args);
        } else {
         //本文返回值是User对象,所以走这
         //获取方法入参参数
          Object param = method.convertArgsToSqlCommandParam(args);
          //执行SqlSession查询单个方法,传入类路径和入参参数
          result = sqlSession.selectOne(command.getName(), param);
        }
        break;
      case FLUSH:
        result = sqlSession.flushStatements();
        break;
      default:
        throw new BindingException("Unknown execution method for: " + command.getName());
    }
    if (result == null && method.getReturnType().isPrimitive() && !method.returnsVoid()) {
      throw new BindingException("Mapper method '" + command.getName() 
          + " attempted to return null from a method with a primitive return type (" + method.getReturnType() + ").");
    }
    return result;
  }

请看DefaultSqlSession对象中的SelectOne和selectList方法

 @Override
  public <T> T selectOne(String statement, Object parameter) {
    // Popular vote was to return null on 0 results and throw exception on too many.
    //statement类路径,parameter入参参数
    List<T> list = this.<T>selectList(statement, parameter);
    if (list.size() == 1) {
    //由于是查询单个则返回list集合的第一个元素
      return list.get(0);
    } else if (list.size() > 1) {
    //查询单个,如果查询出的数据数量大于1,则抛出TooManyResultsException异常
      throw new TooManyResultsException("Expected one result (or null) to be returned by selectOne(), but found: " + list.size());
    } else {
      return null;
    }
  }
 @Override
  public <E> List<E> selectList(String statement, Object parameter) {
    return this.selectList(statement, parameter, RowBounds.DEFAULT);
  }

  @Override
  public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
    try {
    //根据类路径在Configuration的配置类中获取MappedStatement
   	//  protected final Map<String, MappedStatement> mappedStatements = new StrictMap<MappedStatement>("Mapped Statements collection");
   	//MappedStatement中封装了Configuration和类路径以及sql语句映射xml文件和返回值类型以及sql语句类型还有Sql语句,拦截器就是通过拦截该对象来生成日志的,因为它内部封装了语句执行的所有内容,此时部分属性仍为空,需要后续传入。
      MappedStatement ms = configuration.getMappedStatement(statement);
      //在SqlSession中调用Executor执行器执行sql语句,由于类型(BATCH,REUSE,SIMPLE)执行器被封装CachingExecutor对象中,而CachingExecutor对象由被动态代理了(本文配置了拦截器),所有会调用Plugin中的invoke方法,优先执行拦截器中的方法.
      return executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
    } catch (Exception e) {
      throw ExceptionFactory.wrapException("Error querying database.  Cause: " + e, e);
    } finally {
      ErrorContext.instance().reset();
    }
  }
  
//org.apache.ibatis.plugin.Plugin
  @Override
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    try {
    //这里的signature指的是拦截器上配置的@Signature注解,signatureMap的key值封装了执行器类信息,value值是根据配置的@Signature注解内的信息封装的Method方法
      Set<Method> methods = signatureMap.get(method.getDeclaringClass());
      if (methods != null && methods.contains(method)) {
      	//执行配置拦截器内的intercept方法
        return interceptor.intercept(new Invocation(target, method, args));
      }
      //如果该方法未被拦截则直接返回
      return method.invoke(target, args);
    } catch (Exception e) {
      throw ExceptionUtil.unwrapThrowable(e);
    }
  }
  
//补充配置拦截器的代码如下:
@Intercepts({
        @Signature(type = Executor.class, method = "update", args = {MappedStatement.class,
                Object.class}),
        @Signature(type = Executor.class, method = "query", args = {MappedStatement.class,
                Object.class, RowBounds.class, ResultHandler.class})
})
public class MybatisPlugin implements Interceptor {


    public Object intercept(Invocation invocation) throws Throwable {
        Object[] args = invocation.getArgs();
        MappedStatement mappedStatement = (MappedStatement)invocation.getArgs()[0];
        String sql = buildMethodArgNameMapAndResultSql(mappedStatement, args);
        System.out.println("sql = " + sql);
        //根据invocation中的method对象类型执行相应方法,如何又是代理对象则继续执行一遍拦截器方法,当执行到Executor时,结束代理,
        return invocation.proceed();
    }

    public Object plugin(Object target) {
        return Plugin.wrap(target,this);
    }

    public void setProperties(Properties properties) {

    }

    public String buildMethodArgNameMapAndResultSql(MappedStatement mappedStatement, Object[] args){
        Map<String,Object> nameArgMap = Maps.newHashMap();
       Object parameterValue = null;
        if(args.length>1){
            //获取参数,if语句成立,表示sql语句有参数,参数格式是map形式
            parameterValue = args[1];
        }else {
            throw new RuntimeException("参数为空");
        }

        String[] split = parameterValue.toString().substring(1,parameterValue.toString().lastIndexOf('}')).split(",");
        String[] names = new String[split.length];
        final int[] i = {0};
        Arrays.asList(split).forEach(parameter -> {
            String name = parameter.substring(0,parameter.lastIndexOf('=')).trim();
            String value = parameter.substring(parameter.lastIndexOf('=')+1,parameter.length()).trim();
            names[i[0]] = name;
            i[0] = i[0] +1;
            nameArgMap.put(name,value);
        });
        BoundSql boundSql = mappedStatement.getSqlSource().getBoundSql(parameterValue);
        ParameterMapping parameterMapping = boundSql.getParameterMappings().get(0);
        String parameterKey = parameterMapping.getProperty();
        System.out.println("parameterKey = " + parameterKey);
        String sql = boundSql.getSql();
        StringBuilder resultSql = getSql(nameArgMap, sql, names);
        return resultSql.toString();
    }
    public StringBuilder getSql(Map<String,Object> map ,String sql,String[] names){
        StringBuilder sb = new StringBuilder();
        System.out.println("map:"+map);
        System.out.println(sql);
        int length =sql.length();
        for (int i = 0; i < length; i++) {
            char c =sql.charAt(i);
            if(c == '?'){
                for (int j = 0;j<names.length;j++){
                    if(sb.indexOf(names[j])!=-1){
                        sb.append(map.get(names[j]));
                        names[j] = "  ";
                    }
                }

                continue;
            }
            sb.append(sql.charAt(i));
        }
        return sb;
    }
}

CachingExecutor执行器的query方法

@Override
  public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
  //根据MappedStatement获取sql语句,以及入参参数
    BoundSql boundSql = ms.getBoundSql(parameterObject);
    //做一层缓存
    CacheKey key = createCacheKey(ms, parameterObject, rowBounds, boundSql);
    return query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
  }
  
 @Override
  public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql)
      throws SQLException {
    Cache cache = ms.getCache();
    //使用CachingExecutor的目的就是多次查询时,无需重复访问数据库,Mybatis做了缓存执行器,可以当重复请求时则在该处获取缓存直接返回了
    if (cache != null) {
      flushCacheIfRequired(ms);
      if (ms.isUseCache() && resultHandler == null) {
        ensureNoOutParams(ms, parameterObject, boundSql);
        @SuppressWarnings("unchecked")
        List<E> list = (List<E>) tcm.getObject(cache, key);
        if (list == null) {
          list = delegate.<E> query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
          tcm.putObject(cache, key, list); // issue #578 and #116
        }
        return list;
      }
    }
    //deletate则为配置的执行器类型,由于第一次访问,无缓存则直接走配置类型的queyr方法,而Batch和Reuse以及Simple执行器的父类都是BaseExecutor执行器,所以会先走父类
    return delegate.<E> query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
  }

BaseExecutor的public List query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) =>BaseExecutor的 private List queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql)方法

//org.apache.ibatis.executor.BaseExecutor

private <E> List<E> queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
    List<E> list;
    //将sql语句相关信息放进localCache缓存中,当执行BaseExecutor的queyr方法时会先去localCache中取sql语句的信息,取到了直接返回,则无需访问数据库了
    localCache.putObject(key, EXECUTION_PLACEHOLDER);
    try {
    	//BaseExecutor的doQuery方法是一个抽象方法,所以会交给子类执行,此时就到了配置的BatchExecutor(本文环境这样配置的,默认为Simple)出场了
      list = doQuery(ms, parameter, rowBounds, resultHandler, boundSql);
    } finally {
      localCache.removeObject(key);
    }
    //查询结束后将sql语句信息和查询的结果集合封装到localCache中,也就是一级缓存~
    localCache.putObject(key, list);
    if (ms.getStatementType() == StatementType.CALLABLE) {
      localOutputParameterCache.putObject(key, parameter);
    }
    return list;
  }
  
org.apache.ibatis.executor.BatchExecutor
@Override
  public <E> List<E> doQuery(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql)
      throws SQLException {
    Statement stmt = null;
    try {
      flushStatements();
      //获取配置类
      Configuration configuration = ms.getConfiguration();
	  //生成StatementHandler,看下列补充
      StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameterObject, rowBounds, resultHandler, boundSql);
      Connection connection = getConnection(ms.getStatementLog());
      stmt = handler.prepare(connection, transaction.getTimeout());
      handler.parameterize(stmt);
      return handler.<E>query(stmt, resultHandler);
    } finally {
      closeStatement(stmt);
    }
  }

//补充:
org.apache.ibatis.session.Configuration
public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
//生成statementHandler的目的为了处理statement,请看下列补充2
    StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql);
    //这里的动态代理操作和执行器的动态代理操作一模一样,套娃式代理,配置了几个拦截器就代理几次,最终就调用几次拦截器中的intercept的方法
    statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler);
    return statementHandler;
 }
//补充2:
org.apache.ibatis.executor.statement.RoutingStatementHandler
public RoutingStatementHandler(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {

    switch (ms.getStatementType()) {
      case STATEMENT:
      	//无需预处理
        delegate = new SimpleStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
        break;
      case PREPARED:
      	//需要预处理
      	//本文走这
        delegate = new PreparedStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
        break;
      case CALLABLE:
      	//存储过程的调用
        delegate = new CallableStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
        break;
      default:
        throw new ExecutorException("Unknown statement type: " + ms.getStatementType());
    }

  }

确定好StatementHandler的类型PreparedStatementHandler后,最终会生成它的父类BaseStatementHandler

org.apache.ibatis.executor.statement.BaseStatementHandler

 protected BaseStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
    this.configuration = mappedStatement.getConfiguration();
    this.executor = executor;
    this.mappedStatement = mappedStatement;
    this.rowBounds = rowBounds;

    this.typeHandlerRegistry = configuration.getTypeHandlerRegistry();
    this.objectFactory = configuration.getObjectFactory();

    if (boundSql == null) { // issue #435, get the key before calculating the statement
      generateKeys(parameterObject);
      boundSql = mappedStatement.getBoundSql(parameterObject);
    }

    this.boundSql = boundSql;
	
	//重点在这,当statementHandler的类型确定好后,会生成相应的参数处理器parameterHandler和结果集处理器resultSetHandler
    this.parameterHandler = configuration.newParameterHandler(mappedStatement, parameterObject, boundSql);
    this.resultSetHandler = configuration.newResultSetHandler(executor, mappedStatement, rowBounds, parameterHandler, resultHandler, boundSql);
  }

//补充:
//生成ParameterHandler和ResultSetHandler的过程同样会进行套娃式动态代理,为了调用拦截器的intercept方法,根据配置的签名拦截相应方法类型
//Configuration中
  public ParameterHandler newParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql) {
    ParameterHandler parameterHandler = mappedStatement.getLang().createParameterHandler(mappedStatement, parameterObject, boundSql);
    parameterHandler = (ParameterHandler) interceptorChain.pluginAll(parameterHandler);
    return parameterHandler;
  }
  public ResultSetHandler newResultSetHandler(Executor executor, MappedStatement mappedStatement, RowBounds rowBounds, ParameterHandler parameterHandler,
      ResultHandler resultHandler, BoundSql boundSql) {
    ResultSetHandler resultSetHandler = new DefaultResultSetHandler(executor, mappedStatement, parameterHandler, resultHandler, boundSql, rowBounds);
    resultSetHandler = (ResultSetHandler) interceptorChain.pluginAll(resultSetHandler);
    return resultSetHandler;
  }

当StatementHandelr实例化完成后,就可以开始准备访问数据库了,回到doQuery方法

org.apache.ibatis.executor.BatchExecutor
@Override
  public <E> List<E> doQuery(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql)
      throws SQLException {
    Statement stmt = null;
    try {
      flushStatements();
      //获取配置类
      Configuration configuration = ms.getConfiguration();
	  //生成StatementHandler,看下列补充
      StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameterObject, rowBounds, resultHandler, boundSql);
     //获取连接,JDBC操作开始了
      Connection connection = getConnection(ms.getStatementLog());
      //看补充
      stmt = handler.prepare(connection, transaction.getTimeout());
      //调用StatementHandler处理生成的statement,其实是调用内部的parameterHandler处理参数看补充2
      handler.parameterize(stmt);
      //处理完sql语句的参数后,调用StatementHandler的query方法,resultHandelr为null,其实就是调用PreparedStatementHandler中的resultSetHandler对象,将sql语句的执行结果传入进行参数处理
      return handler.<E>query(stmt, resultHandler);
    } finally {
      closeStatement(stmt);
    }
  }
//补充:
//调用BaseStatement的prepare方法
 @Override
  public Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException {
    ErrorContext.instance().sql(boundSql.getSql());
    Statement statement = null;
    try {
     //JDBC操作,操作数据库,生成Statement对象
      statement = instantiateStatement(connection);
      setStatementTimeout(statement, transactionTimeout);
      setFetchSize(statement);
      return statement;
    } catch (SQLException e) {
      closeStatement(statement);
      throw e;
    } catch (Exception e) {
      closeStatement(statement);
      throw new ExecutorException("Error preparing statement.  Cause: " + e, e);
    }
  }
  
//补充2
org.apache.ibatis.executor.statement.PreparedStatementHandler
 @Override
  public void parameterize(Statement statement) throws SQLException {
  	//将方法入参参数代替sql语句中的#{id},这里就不进行深入了,内部就是算法对参数处理
    parameterHandler.setParameters((PreparedStatement) statement);
  }

继续看Executor的doQuery方法的返回值是handler.query(stmt, resultHandler);中PreparedStatementHandler的query方法

@Override
  public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {

    PreparedStatement ps = (PreparedStatement) statement;
    //执行sql语句
    ps.execute();
    //将PreparedStatement传入resultSetHandler进行参数处理
    return resultSetHandler.<E> handleResultSets(ps);
  }

PreparedStatement中的ResultSet执行结果如下图所示:
在这里插入图片描述
继续看ResultSetHandler的handleResultSets方法

org.apache.ibatis.executor.resultset.DefaultResultSetHandler
@Override
  public List<Object> handleResultSets(Statement stmt) throws SQLException {
    ErrorContext.instance().activity("handling results").object(mappedStatement.getId());
	//结果集容器
    final List<Object> multipleResults = new ArrayList<Object>();

    int resultSetCount = 0;
    //处理statement中ResultSet的结果集,将列名和类型读取出来包装在ResultSetWrapper中
    ResultSetWrapper rsw = getFirstResultSet(stmt);
    List<ResultMap> resultMaps = mappedStatement.getResultMaps();
    int resultMapCount = resultMaps.size();
    validateResultMapsCount(rsw, resultMapCount);
    while (rsw != null && resultMapCount > resultSetCount) {
      //映射的实体类对象,实体类中属性所需的类型
      ResultMap resultMap = resultMaps.get(resultSetCount);
      //将数据库中读取的数据类型rsw和实体类属性的类型resultMap和一个结果集容器(此时为空)传入,此时处理结果集.
      handleResultSet(rsw, resultMap, multipleResults, null);
      rsw = getNextResultSet(stmt);
      cleanUpAfterHandlingResultSet();
      resultSetCount++;
    }

    String[] resultSets = mappedStatement.getResultSets();
    if (resultSets != null) {
      while (rsw != null && resultSetCount < resultSets.length) {
        ResultMapping parentMapping = nextResultMaps.get(resultSets[resultSetCount]);
        if (parentMapping != null) {
          String nestedResultMapId = parentMapping.getNestedResultMapId();
          ResultMap resultMap = configuration.getResultMap(nestedResultMapId);
          handleResultSet(rsw, resultMap, null, parentMapping);
        }
        rsw = getNextResultSet(stmt);
        cleanUpAfterHandlingResultSet();
        resultSetCount++;
      }
    }

    return collapseSingleResultList(multipleResults);
  }

handleResultSet(rsw, resultMap, multipleResults, null);=>handleRowValues(rsw, resultMap, defaultResultHandler, rowBounds, null);=> handleRowValuesForSimpleResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);均为结果集处理流程

//org.apache.ibatis.executor.resultset.DefaultResultSetHandler

 private void handleRowValuesForSimpleResultMap(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping)
      throws SQLException {
    DefaultResultContext<Object> resultContext = new DefaultResultContext<Object>();
    skipRows(rsw.getResultSet(), rowBounds);
    while (shouldProcessMoreRows(resultContext, rowBounds) && rsw.getResultSet().next()) {
      //封装了数据库字段名,实体类属性类型,javaType和jdbcType等信息都封装在该类中,结果集映射
      ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(rsw.getResultSet(), resultMap, null);
	  //重点在这,结果集处理
      Object rowValue = getRowValue(rsw, discriminatedResultMap);
      storeObject(resultHandler, resultContext, rowValue, parentMapping, rsw.getResultSet());
    }
  }
  
private Object getRowValue(ResultSetWrapper rsw, ResultMap resultMap) throws SQLException {
    final ResultLoaderMap lazyLoader = new ResultLoaderMap();
    //返回结果集对象!如果不为空直接返回了,也就是结果集映射结束了,查询出的对象返回。
    Object rowValue = createResultObject(rsw, resultMap, lazyLoader, null);
    if (rowValue != null && !hasTypeHandlerForResultObject(rsw, resultMap.getType())) {
      final MetaObject metaObject = configuration.newMetaObject(rowValue);
      boolean foundValues = this.useConstructorMappings;
      if (shouldApplyAutomaticMappings(resultMap, false)) {
        foundValues = applyAutomaticMappings(rsw, resultMap, metaObject, null) || foundValues;
      }
      foundValues = applyPropertyMappings(rsw, resultMap, metaObject, lazyLoader, null) || foundValues;
      foundValues = lazyLoader.size() > 0 || foundValues;
      rowValue = (foundValues || configuration.isReturnInstanceForEmptyRow()) ? rowValue : null;
    }
    return rowValue;
 }

  private Object createResultObject(ResultSetWrapper rsw, ResultMap resultMap, ResultLoaderMap lazyLoader, String columnPrefix) throws SQLException {
    this.useConstructorMappings = false; // reset previous mapping result
    final List<Class<?>> constructorArgTypes = new ArrayList<Class<?>>();
    final List<Object> constructorArgs = new ArrayList<Object>();
   	//!获取结果集对象
    Object resultObject = createResultObject(rsw, resultMap, constructorArgTypes, constructorArgs, columnPrefix);
    if (resultObject != null && !hasTypeHandlerForResultObject(rsw, resultMap.getType())) {
      final List<ResultMapping> propertyMappings = resultMap.getPropertyResultMappings();
      for (ResultMapping propertyMapping : propertyMappings) {
        // issue gcode #109 && issue #149
        if (propertyMapping.getNestedQueryId() != null && propertyMapping.isLazy()) {
          resultObject = configuration.getProxyFactory().createProxy(resultObject, lazyLoader, configuration, objectFactory, constructorArgTypes, constructorArgs);
          break;
        }
      }
    }
    //设置当前映射结果
    this.useConstructorMappings = (resultObject != null && !constructorArgTypes.isEmpty()); 
    return resultObject;
  }

 private Object createResultObject(ResultSetWrapper rsw, ResultMap resultMap, List<Class<?>> constructorArgTypes, List<Object> constructorArgs, String columnPrefix)
      throws SQLException {
      //返回的对象Class类信息
    final Class<?> resultType = resultMap.getType();
    //根据类信息和反射工厂生成MetaClass对象
    final MetaClass metaType = MetaClass.forClass(resultType, reflectorFactory);
    //如果返回值对象中使用了参数构造器,构造器中封装的属性类型封装在该List集合中(本文使用了有参构造器)
    final List<ResultMapping> constructorMappings = resultMap.getConstructorResultMappings();
    if (hasTypeHandlerForResultObject(rsw, resultType)) {
      return createPrimitiveResultObject(rsw, resultMap, columnPrefix);
    } else if (!constructorMappings.isEmpty()) {
    //如果对象的有参构造器不为空,则使用参数构造器创建返回结果集对象。
      return createParameterizedResultObject(rsw, resultType, constructorMappings, constructorArgTypes, constructorArgs, columnPrefix);
    } else if (resultType.isInterface() || metaType.hasDefaultConstructor()) {
      return objectFactory.create(resultType);
    } else if (shouldApplyAutomaticMappings(resultMap, false)) {
      return createByConstructorSignature(rsw, resultType, constructorArgTypes, constructorArgs, columnPrefix);
    }
    throw new ExecutorException("Do not know how to create an instance of " + resultType);
  }
  
Object createParameterizedResultObject(ResultSetWrapper rsw, Class<?> resultType, List<ResultMapping> constructorMappings,
                                         List<Class<?>> constructorArgTypes, List<Object> constructorArgs, String columnPrefix) {
    boolean foundValues = false;
    //根据构造器中的入参参数类型数量遍历,封装在constructorArgs结合中
    for (ResultMapping constructorMapping : constructorMappings) {
      final Class<?> parameterType = constructorMapping.getJavaType();
      final String column = constructorMapping.getColumn();
      final Object value;
      try {
        if (constructorMapping.getNestedQueryId() != null) {
          value = getNestedQueryConstructorValue(rsw.getResultSet(), constructorMapping, columnPrefix);
        } else if (constructorMapping.getNestedResultMapId() != null) {
          final ResultMap resultMap = configuration.getResultMap(constructorMapping.getNestedResultMapId());
          value = getRowValue(rsw, resultMap);
        } else {
          final TypeHandler<?> typeHandler = constructorMapping.getTypeHandler();
          //其实就是根据参数的不同类型去ResultSet中根据列名取值
          //如此时是String类型就好在typeHandler下的子类StringTypeHandler中的getNullableResult方法调用ResultSet的getString方法
          //(还是JDBC操作)
          value = typeHandler.getResult(rsw.getResultSet(), prependPrefix(column, columnPrefix));
        }
      } catch (ResultMapException e) {
        throw new ExecutorException("Could not process result for mapping: " + constructorMapping, e);
      } catch (SQLException e) {
        throw new ExecutorException("Could not process result for mapping: " + constructorMapping, e);
      }
      constructorArgTypes.add(parameterType);
      //传入集合中
      constructorArgs.add(value);
      foundValues = value != null || foundValues;
    }
    return foundValues ? objectFactory.create(resultType, constructorArgTypes, constructorArgs) : null;
  }


//补充本文的实体类:
@Data
@ToString
@AllArgsConstructor
public class User {
    private Integer id;
    private String username;
    private Timestamp birthday;
    private String sex;
    private String address;

}

objectFactory.create(resultType, constructorArgTypes, constructorArgs),该方法根据相应实体类中的参数构造器实例化对象。

org.apache.ibatis.reflection.factory.DefaultObjectFactory
@Override
  public <T> T create(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) {
    Class<?> classToCreate = resolveInterface(type);
    return (T) instantiateClass(classToCreate, constructorArgTypes, constructorArgs);
  }
  
 <T> T instantiateClass(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) {
    try {
      Constructor<T> constructor;
      if (constructorArgTypes == null || constructorArgs == null) {
        constructor = type.getDeclaredConstructor();
        if (!constructor.isAccessible()) {
          constructor.setAccessible(true);
        }
        return constructor.newInstance();
      }
      //constructorArgTypes参数类型封装不为空直接走这
      //获取参数构造器
      constructor = type.getDeclaredConstructor(constructorArgTypes.toArray(new Class[constructorArgTypes.size()]));
      if (!constructor.isAccessible()) {
        constructor.setAccessible(true);
      }
      //调用JDK代码实例化对象,返回对象
      return constructor.newInstance(constructorArgs.toArray(new Object[constructorArgs.size()]));
    } catch (Exception e) {
      StringBuilder argTypes = new StringBuilder();
      if (constructorArgTypes != null && !constructorArgTypes.isEmpty()) {
        for (Class<?> argType : constructorArgTypes) {
          argTypes.append(argType.getSimpleName());
          argTypes.append(",");
        }
        argTypes.deleteCharAt(argTypes.length() - 1); // remove trailing ,
      }
      StringBuilder argValues = new StringBuilder();
      if (constructorArgs != null && !constructorArgs.isEmpty()) {
        for (Object argValue : constructorArgs) {
          argValues.append(String.valueOf(argValue));
          argValues.append(",");
        }
        argValues.deleteCharAt(argValues.length() - 1); // remove trailing ,
      }
      throw new ReflectionException("Error instantiating " + type + " with invalid types (" + argTypes + ") or values (" + argValues + "). Cause: " + e, e);
    }
  }

此时其实一个完整的返回值对象已经构建完毕,回到DefaultResultSetHandler的createResultObject创建结果集对象这里,
这里存在一个小问题可以参考我的另一篇博客分析:类型处理

 private Object createResultObject(ResultSetWrapper rsw, ResultMap resultMap, List<Class<?>> constructorArgTypes, List<Object> constructorArgs, String columnPrefix)
      throws SQLException {
    final Class<?> resultType = resultMap.getType();
    final MetaClass metaType = MetaClass.forClass(resultType, reflectorFactory);
    final List<ResultMapping> constructorMappings = resultMap.getConstructorResultMappings();
    if (hasTypeHandlerForResultObject(rsw, resultType)) {
      return createPrimitiveResultObject(rsw, resultMap, columnPrefix);
    } else if (!constructorMappings.isEmpty()) {
    //执行结束,返回结果集
      return createParameterizedResultObject(rsw, resultType, constructorMappings, constructorArgTypes, constructorArgs, columnPrefix);
    } else if (resultType.isInterface() || metaType.hasDefaultConstructor()) {
      return objectFactory.create(resultType);
    } else if (shouldApplyAutomaticMappings(resultMap, false)) {
      return createByConstructorSignature(rsw, resultType, constructorArgTypes, constructorArgs, columnPrefix);
    }
    throw new ExecutorException("Do not know how to create an instance of " + resultType);
  }

此时结果集对象构建完成,ResultSetHandler的工作也完成了,执行结束后会将该对象存储到MetaObject对象中,一路返回到BatchExecutor的doQuery方法

@Override
  public <E> List<E> doQuery(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql)
      throws SQLException {
    Statement stmt = null;
    try {
      flushStatements();
      Configuration configuration = ms.getConfiguration();
      // StatementHandler
      StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameterObject, rowBounds, resultHandler, boundSql);
      Connection connection = getConnection(ms.getStatementLog());
      stmt = handler.prepare(connection, transaction.getTimeout());
      handler.parameterize(stmt);
      //ResultSetHandler
      return handler.<E>query(stmt, resultHandler);
    } finally {
      closeStatement(stmt);
    }
  }
  //此时一个完整对象已经构造完成了,源码分析结束。

总结:通过调用MapperProxy代理对象的invoke方法确定SQL语句的类型,调用SqlSession的相应方法,SqlSession会去调用Executor执行器,但由于使用了拦截器,执行器已被Plugin对象中的wrap方法调用创建了代理对象,所以会走Plugin对象的invoke方法,调用拦截器的intercept方法,然后才会去执行CachingExecutor缓存执行器的方法,如query查询,优先去缓存中取,如果换成中有执行结果则直接返回,没有则调用相应的执行器取执行sql语句,Executor会去创建一个StatementHandler对象,StatementHandler对象中封装了Preparestatement和ResultsetHandler对象,Preparestatement用于处理sql语句的参数,ResultSetHandler用于处理statement执行完后的ResultSet结果集对象,最终返回相应的实体类对象。返回到Executo执行器中,将返回结果作为value值放进localCache一级缓存中,方法的类路径和执行语句等信息作为key值,下次访问当调用执行器时,会先检测localCache中是否有该方法的缓存,有则直接返回不做数据库访问了。
在这里插入图片描述

6.后言

大总结下:
mybatis的执行流程就是:根据配置文件生成一个Configuration配置类对象从而构建出一个SqlSessionFactory工厂,该工厂通过实例化一个执行器Executor并确定执行器的类型,将执行器放入CachingExecutor执行器中(委托模式),若配置了拦截器,此时还会调用Plugin对象的wrap方法进行动态代理生成代理对象和事务控制器Trasacation生成一个SqlSesson对象,再从MapperRegister注册器中根据类信息取出注册的MapperProxyFactory工厂,再由该工厂根据SqlSession生产了一个并进行了一层动态代理mapperProxy对象,调用mapperProxy对象会优先执行MapperProxy中的invoke方法,根据策略模式,调用sqlsession的相应方法,然后会去让Executor去执行sql语句,如果是SELECT类型同时又需要处理参数,它会创建一个statementHandler对象,若有拦截器配置,该对象同样会被动态代理,同时实例化Preparestatement和ResultSetHandler对象,同样,若有拦截器配置,这两个同样会被动态代理(此时可以得知,Mybatis拦截器可以在执行器执行时,预处理SQL语句时,处理返回集结果时配置签名进行拦截),Preparestatement用于预处理SQL语句,ResultSetHandler用于处理ResultSet执行sql语句后数据库返回的数据,处理完后,放入localCache一级缓存中,这就是Mybatis的基本执行流程。
谢谢阅读,如有错误,还请斧正。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值