Mybatis源码学习(四)

Mybatis源码分析(四)

上回我们分析了Mybatis解析mapper映射文件的代码,我们继续上次的分析,开始mybatis执行sql语句的流程,话不多说咱们上代码!!!!!!

上回总结

​ 上回我们分析了mybatis解析mapper映射文件的过程

  1. 解析***Mapper.xml文件的mapper标签;
  2. 解析select|insert|update|delete标签;
  3. 解析动态sql语句将sql语句解析后封装为一个SqlSource
  4. 通过builderAssistant(构建者助手),构建MappedStatement对象;
  5. MappedStatement对象放入configuration对象中的mappedStatementsmap中;

最终我们的到SqlSessionFactory对象,封装后具体结构如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-evWs40J0-1605862861728)(C:\Users\李昊\AppData\Roaming\Typora\typora-user-images\image-20201118205559442.png)]

开始执行流程
创建SqlSession对象
  1. 回到我们的main方法中,得到SqlSessionFactory对象后,调用sqlSessionFactory.openSession()方法创建SqlSession对象;

    //通过工厂生产一个sqlsession对象
    SqlSession sqlSession = sqlSessionFactory.openSession();
    
    //调用sqlSessionFactory的openSession方法
     @Override
    public SqlSession openSession() {
       return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false);
     }
    
    private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
        Transaction tx = null;
        try {
          // 获取数据源环境信息
          final Environment environment = configuration.getEnvironment();
          // 获取事务工厂
          final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
          // 获取JdbcTransaction或者ManagedTransaction
          tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
          // 创建Executor执行器
          final Executor executor = configuration.newExecutor(tx, execType);
          // 创建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();
        }
      }
    

    获取事务工厂创建TransactionFactory我们使用的是jdbc,所以创建的是JdbcTransactionFactory,使用JDBC的事务管理机制,就是利用java.sql.Connection对象完成对事务的提交),通过工厂创建Transaction(我们使用的是jdbc,所以创建的是JdbcTransaction);创建Executor执行器,用来操作数据库;

    //Executor执行器
    public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
    		executorType = executorType == null ? defaultExecutorType : executorType;
    		executorType = executorType == null ? ExecutorType.SIMPLE : executorType;
    		Executor executor;
    		if (ExecutorType.BATCH == executorType) {
    			// 批处理执行器
    			executor = new BatchExecutor(this, transaction);
    		} else if (ExecutorType.REUSE == executorType) {
    			// 可重用执行器
    			executor = new ReuseExecutor(this, transaction);
    		} else {
    			// 简单执行器
    			executor = new SimpleExecutor(this, transaction);
    		}
    		// 如果开启缓存(默认是开启的),则使用缓存执行器
    		if (cacheEnabled) {
    			executor = new CachingExecutor(executor);
    		}
    		// 插件执行
    		executor = (Executor) interceptorChain.pluginAll(executor);
    		return executor;
    	}
    

    我们这里创建了一个简单执行器,mybatis默认是开启了一级缓存的,又创建缓存执行器,后面用来执行我们解析好的sql语句,最后创建了一个DefaultSqlSession对象;

  2. 通过SqlSession获取接口的代理对象

        //通过SqlSession获取一个PersionMapper接口的代理对象
        PersonMapper mapper = sqlSession.getMapper(PersonMapper.class);
    
        //调用Sqlsession的getMapper调用configuration中的getMapper方法
        public <T> T getMapper(Class<T> type) {
            // 从Configuration对象中,根据Mapper接口,获取Mapper代理对象
            return configuration.<T>getMapper(type, this);
        }
    	//从configuration中取到之前封装好的mapperRegistry
    	//里面有之前放进去的代理对象工厂
    	public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
    		return mapperRegistry.getMapper(type, sqlSession);
    	}
    	//调用mapperRegistry的getMapper方法取到Mapper代理对象工厂
    	//key为接口的class对象,value为接口的代理对象工厂
    	public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
            // 根据Mapper接口的类型,从Map集合中获取Mapper代理对象工厂
            final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
            if (mapperProxyFactory == null) {
              throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
            }
            try {
              // 通过MapperProxyFactory生产MapperProxy,通过MapperProxy产生Mapper代理对象
              return mapperProxyFactory.newInstance(sqlSession);
            } catch (Exception e) {
              throw new BindingException("Error getting mapper instance. Cause: " + e, e);
            }
      	}
    
    

    mapperRegistry中取到mapper的代理对象工厂,并生产MapperProxy,通过MapperProxy产生Mapper代理对象;

创建Mapper代理对象
		// 通过MapperProxyFactory生产MapperProxy,通过MapperProxy产生Mapper代理对象
        return mapperProxyFactory.newInstance(sqlSession);
		
		//调用生产出来的mapperProxyFactory的newInstance方法,生产mapperProxy
		public T newInstance(SqlSession sqlSession) {
			// 创建基于JDK实现的Mapper代理对象
    		final MapperProxy<T> mapperProxy = new MapperProxy<>(sqlSession, mapperInterface, methodCache);
    		return newInstance(mapperProxy);
  		}
		//通过mapperProxy创建Mapper接口代理对象
		protected T newInstance(MapperProxy<T> mapperProxy) {
			// 使用JDK动态代理方式,生成代理对象
    		return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
  		}

这里通过MapperProxyFactory生产了一个MapperProxy对象,通过MapperProxy给予JDK的动态代理创建了一个mapper代理对象;

  1. 执行代理对象的seleceById方法

    		//创建入参对象并赋值
    		Person person1 = new Person();
            person1.setId("1");
            //执行selectById方法传入入参 "1"
            Person person = mapper.selectById(person1);
    		
    		//
    		public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                try {
                  // 是Interface接口还是Object类
                  // 如果方法是Object类自带的方法,比如没有被重写的 equals toString, hashcode 等,还是执行原来的方法
        		  // getDeclaringClass()返回表示声明由此 Method 对象表示的方法的类或接口的 Class 对象。
                  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);
                }
                // 如果不是object的自带方法,先去  Map<Method, MapperMethod> methodCache中找是否已经存在这个method了
                // 没有就将method封装成MapperMethod存进mehtodCache中然后返回MapperMethod
                final MapperMethod mapperMethod = cachedMapperMethod(method);
                // 然后执行MapprMehtod的execute方法(执行sqlsession的方法)
                return mapperMethod.execute(sqlSession, args);
            }
    

    执行代理对象的seleceById方法,会进入MapperProxy.invoke()方法,判断当前是Interface接口还是Object类,判断有没有缓存这个方法,最后执行MapperProxy.execute()方法;

  2. 执行MapperProxy.execute()方法

    //执行MapperProxy.execute()执行SQL脚本,得到结果对象,然后转换成对应method返回类型的对象
    public Object execute(SqlSession sqlSession, Object[] args) {
        Object result;
        //判断Sql指令类型
        switch (command.getType()) {
          //插入指令
          case INSERT: {
            //构建sql脚本参数名-参数对象映射集合;
        	Object param = method.convertArgsToSqlCommandParam(args);
            //执行插入Sql脚本,然后将更新记录数转换成method所需要的返回类型对象
            result = rowCountResult(sqlSession.insert(command.getName(), param));
            break;
          }
          //修改指令
          case UPDATE: {
            //构建sql脚本参数名-参数对象映射集合;
            Object param = method.convertArgsToSqlCommandParam(args);
            //执行修改Sql脚本,然后将更新记录数转换成method所需要的返回类型对象
            result = rowCountResult(sqlSession.update(command.getName(), param));
            break;
          }
          //删除指令
          case DELETE: {
            //构建sql脚本参数名-参数对象映射集合;
            Object param = method.convertArgsToSqlCommandParam(args);
            result = rowCountResult(sqlSession.delete(command.getName(), param));
            break;
          }
          //查询指令
          case SELECT:
            //如果method返回类型为void 而且 method有ResultHandler类型参数
            if (method.returnsVoid() && method.hasResultHandler()) {
              //用ResultHandler执行查询sql
              executeWithResultHandler(sqlSession, args);
              //处理结果赋值为ull
              result = null;
              //如果method返回类型为Collection的子类或者返回类型是数组
            } else if (method.returnsMany()) {
              /**
               * 执行查询SQL,默认返回结果对象集合,但如果method返回类型为数组,该方法就会自动将结果对象集合
               * 转换成数组;如果method返回类型为自定义的Collection实现类,该方法也会将结果对象集合的元素添加到
               * 自定义的Collection实现类对象中
               */
              result = executeForMany(sqlSession, args);
              //如果method的返回类型是Map
            } else if (method.returnsMap()) {
              //执行查询SQL,返回结果对象映射赋值给result
              result = executeForMap(sqlSession, args);
              //如果method返回类型是Cursor游标
            } else if (method.returnsCursor()) {
              //执行查询SQL,返回结果对象游标赋值给result
              result = executeForCursor(sqlSession, args);
            } else {
              //构建sql脚本参数名-参数对象映射集合
              Object param = method.convertArgsToSqlCommandParam(args);
              //执行查询SQL,返回结果对象赋值给result
              result = sqlSession.selectOne(command.getName(), param);
              //如果method返回类型为Optional 且 结果对象为null 或者 method返回类型不等于结果对象类型
              if (method.returnsOptional() &&
                  (result == null || !method.getReturnType().equals(result.getClass()))) {
                //如果对象即可能是 null 也可能是非 null,使用 ofNullable() 方法可以防止空指针异常
                result = Optional.ofNullable(result);
              }
            }
            break;
          //刷新指令
          case FLUSH:
            //执行全部等待批处理语句,并将结果封装到BatchResult集合中,然后赋值reuslt
            result = sqlSession.flushStatements();
            break;
          default:
            throw new BindingException("Unknown execution method for: " + command.getName());
        }
        //如果结果对象为null 且 method的返回类型为原始类型 且 method的返回类型不是void
        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;
      }
    
  3. 执行SqlSession.selectOne()方法

    		//执行查询SQL,返回结果对象赋值给result
            result = sqlSession.selectOne(command.getName(), param);
    
    		//执行SqlSession的selectOne方法
    		public <T> T selectOne(String statement, Object parameter) {
                // Popular vote was to return null on 0 results and throw exception on too many.
                List<T> list = this.selectList(statement, parameter);
                if (list.size() == 1) {
                    return list.get(0);
                } else if (list.size() > 1) {
                    throw new TooManyResultsException(
                            "Expected one result (or null) to be returned by selectOne(), but found: " + list.size());
                } else {
                    return null;
                }
    		}
    		
    		//执行SqlSession的selectList
    		public <E> List<E> selectList(String statement, Object parameter) {
    			return this.selectList(statement, parameter, RowBounds.DEFAULT);
    		}
    
    		//执行selectList方法
    		public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
                try {
                    // 根据传入的statementId,获取MappedStatement对象
                    MappedStatement ms = configuration.getMappedStatement(statement);
                    // 调用执行器的查询方法
                    // RowBounds是用来逻辑分页(按照条件将数据从数据库查询到内存中,在内存中进行分页)
                    // wrapCollection(parameter)是用来装饰集合或者数组参数
                    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();
                }
    		}
    

    根据statementId在configuration中取到对应的MappedStatement对象,调用执行器执行查询方法;

调用执行器的查询方法(获取boundSql
	//调用之前创建的CachingExecutor的query方法
  public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler) 			throws SQLException {
	// 获取绑定的SQL语句,比如“SELECT * FROM user WHERE id = ? ”
    BoundSql boundSql = ms.getBoundSql(parameterObject);
    // 生成缓存Key
    CacheKey key = createCacheKey(ms, parameterObject, rowBounds, boundSql);

    return query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
  }

	//调用MappedStatement.getBoundSql()获取绑定的SQL语句
	public BoundSql getBoundSql(Object parameterObject) {
        // 调用SqlSource获取BoundSql
        BoundSql boundSql = sqlSource.getBoundSql(parameterObject);
        List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
        if (parameterMappings == null || parameterMappings.isEmpty()) {
          boundSql = new BoundSql(configuration, boundSql.getSql(), parameterMap.getParameterMappings(), parameterObject);
        }

        // check for nested result maps in parameter mappings (issue #30)
        for (ParameterMapping pm : boundSql.getParameterMappings()) {
          String rmId = pm.getResultMapId();
          if (rmId != null) {
            ResultMap rm = configuration.getResultMap(rmId);
            if (rm != null) {
              hasNestedResultMaps |= rm.hasNestedResultMaps();
            }
          }
        }
        return boundSql;
  	}

	//调用SqlSource获取BoundSql
	public BoundSql getBoundSql(Object parameterObject) {
        //创建动态sql上下文
		DynamicContext context = new DynamicContext(configuration, parameterObject);
		// 此处会调用MixedSqlNode中包含的所有SqlNode的apply方法
		// 此处会处理${},也会处理动态标签
		// 最终将所有的SqlNode信息进行解析之后,追加到DynamicContext对象的StringBuilder对象中
		rootSqlNode.apply(context);
		// 创建SQL信息解析器
		SqlSourceBuilder sqlSourceParser = new SqlSourceBuilder(configuration);
		// 获取入参类型
		Class<?> parameterType = parameterObject == null ? Object.class : parameterObject.getClass();
		// 执行解析:将带有#{}的SQL语句进行解析,然后封装到StaticSqlSource中
		SqlSource sqlSource = sqlSourceParser.parse(context.getSql(), parameterType, context.getBindings());
		// 将解析后的SQL语句还有入参绑定到一起(封装到一个对象中,此时还没有将参数替换到SQL占位符?)
		BoundSql boundSql = sqlSource.getBoundSql(parameterObject);
		for (Map.Entry<String, Object> entry : context.getBindings().entrySet()) {
			boundSql.setAdditionalParameter(entry.getKey(), entry.getValue());
		}
		return boundSql;
	}

创建动态SQL上下文,执行SqlSource中封装的rootSqlNode的apply方法,处理${}、处理动态标签,将处理过后的sql追加到动态SQL上下文中的StringBuilder对象中;

这里详细讲解一下每个SqlNode

SQLNode:每个Xml Node都会解析成对应的SQLNode对象

image-20201119223054796

//SqlNode接口
public interface SqlNode {
	//将各个Sql片段合并到DynamicContext中,拼接为完整的SQL;
  boolean apply(DynamicContext context);
}

//MixedSqlNode
public class MixedSqlNode implements SqlNode {
//记录sql节点中的所有SQL片段
 private final List<SqlNode> contents;

 public MixedSqlNode(List<SqlNode> contents) {
    this.contents = contents;
 }
  @Override
  public boolean apply(DynamicContext context) {
    for (SqlNode sqlNode : contents) {
      sqlNode.apply(context);
    }
    return true;
  }
}

通过解析Sql节点得到的MixedSqlNode结构如下:

20190521234639777

  1. StaticSqlSource:最简单的SqlNode,功能仅仅是将自身记录的text拼接到context上下文中;

    //StaticTextSqlNode
    public class StaticTextSqlNode implements SqlNode {
      private final String text;
    
      public StaticTextSqlNode(String text) {
        this.text = text;
      }
    
      @Override
      public boolean apply(DynamicContext context) {
        context.appendSql(text);
        return true;
      }
    }
    
  2. TextSqlNode:表示包含‘${}’占位符的动态Sql节点;

    	//使用GenericTokenParser解析‘${}’,并直接转换成传入的实际参数
    	public boolean apply(DynamicContext context) {
    		GenericTokenParser parser = createParser(new BindingTokenParser(context, injectionFilter));
    		context.appendSql(parser.parse(text));
    		return true;
    	}
    	//实际参数值获取逻辑方法
    	
    	@Override
    	public String handleToken(String content) {
            // 获取入参对象
            Object parameter = context.getBindings().get("_parameter");
            // 如果入参对象为null或者入参对象是简单类型,不需要关注${}中的名称,直接设置${}的参数名称必须为value
            // 如果content不为value,则取不出数据,会报错
            if (parameter == null) {
                // context.getBindings().put("value", null);
                return "";
            } else if (SimpleTypeRegistry.isSimpleType(parameter.getClass())) {
                // context.getBindings().put("value", parameter);
                return String.valueOf(parameter);
            }
            // 使用Ognl API,通过content中的表达式去获取入参对象中的指定属性值
            // context.getBindings()就是一个ContextMap对象,也是HashMap的子对象
            Object value = OgnlCache.getValue(content, parameter);
            String srtValue = value == null ? "" : String.valueOf(value); // issue #274 return "" instead of "null"
            checkInjection(srtValue);
            return srtValue;
    	}
    
  3. IFSqlNode:if标签平常使用的是最多的,在处理对应的逻辑节点时,主要工作就是通过Ognl表达式和传入的参数进行判断,看传入的参数是否满足if test里的表达式,满足将SQL片段合并到context上下文中。若不满足test则过滤掉这一部分的SQL片段,不添加到context中;

    @Override
    public boolean apply(DynamicContext context) {
        //通过Ognl表达式和传入的参数进行判断,看传入的参数是否满足if test里的表达式
      if (evaluator.evaluateBoolean(test, context.getBindings())) {
        contents.apply(context);
        return true;
      }
      return false;
    }
    
  4. WhereSqlNodeSetSqlNode:都是继承自TrimSqlNode

    1. WhereSqlNode:会传入prefix=WHEREprefixesToOverride=["AND ","OR ","AND\n", "OR\n", "AND\r", "OR\r", "AND\t", "OR\t"];
    2. SetSqlNode:会传入prefix=WHEREprefixesToOverride=[“,”];
    3. 会传入prefix=WHEREprefixesToOverride=[“,”];
  5. TrimSqlNode:<trim /> 标签的SqlNode实现类;

  6. ForEachSqlNode:<foreach /> 标签的SqlNode实现类;

  7. VarDeclSqlNode: <bind /> 标签的SqlNode实现类;

最后动态sql上下文中拼接好的sql为:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8BoYMI8n-1605862861730)(C:\Users\李昊\AppData\Roaming\Typora\typora-user-images\image-20201119230954378.png)]

  1. 解析’#{}’

    //创建SqlSourceBuilder解析#{}
    public SqlSource parse(String originalSql, Class<?> parameterType, Map<String, Object> additionalParameters) {
       ParameterMappingTokenHandler handler = new ParameterMappingTokenHandler(configuration, parameterType,
             additionalParameters);
       // 创建分词解析器
       GenericTokenParser parser = new GenericTokenParser("#{", "}", handler);
       // 解析#{}
       String sql = parser.parse(originalSql);
       // 将解析之后的SQL信息,封装到StaticSqlSource对象中
       // SQL字符串是带有?号的字符串,?相关的参数信息,封装到ParameterMapping集合中
       return new StaticSqlSource(configuration, sql, handler.getParameterMappings());
    }
    
  2. 调用缓存执行器的query方法;

    @Override
     public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql)
         throws SQLException {
    // 获取二级缓存
       Cache cache = ms.getCache();
       if (cache != null) {
         // 刷新二级缓存
         flushCacheIfRequired(ms);
         if (ms.isUseCache() && resultHandler == null) {
           ensureNoOutParams(ms, boundSql);
           // 从二级缓存中查询数据
           @SuppressWarnings("unchecked")
           List<E> list = (List<E>) tcm.getObject(cache, key);
           // 如果二级缓存中没有查询到数据,则查询数据库
           if (list == null) {
             // 委托给BaseExecutor执行
             list = delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
             tcm.putObject(cache, key, list); // issue #578 and #116
           }
           return list;
         }
       }
       // 委托给BaseExecutor执行
       return delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
     }
    

    这里查看是否存在二级缓存,如果存在则查询二级缓存,不存在则查询数据库(前提是开启了mybatis的二级缓存)

  3. 委托给BaseExecutor执行查询方法

    @Override
    public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
      ErrorContext.instance().resource(ms.getResource()).activity("executing a query").object(ms.getId());
      if (closed) {
        throw new ExecutorException("Executor was closed.");
      }
      if (queryStack == 0 && ms.isFlushCacheRequired()) {
        clearLocalCache();
      }
      List<E> list;
      try {
        queryStack++;
        // 从一级缓存中获取数据
        list = resultHandler == null ? (List<E>) localCache.getObject(key) : null;
        if (list != null) {
          handleLocallyCachedOutputParameters(ms, key, parameter, boundSql);
        } else {
       // 如果一级缓存没有数据,则从数据库查询数据
          list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);
        }
      } finally {
        queryStack--;
      }
      if (queryStack == 0) {
        for (DeferredLoad deferredLoad : deferredLoads) {
          deferredLoad.load();
        }
        // issue #601
        deferredLoads.clear();
        if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {
          // issue #482
          clearLocalCache();
        }
      }
      return list;
    }
    

    查看一级缓存是否有数据,没有的话则从数据库查询;

  4. 调用BaseExecutor.queryFromDatabase()方法

    //调用BaseExecutor.queryFromDatabase()方法
    private <E> List<E> queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
        List<E> list;
        //将缓存key存入一级缓存中
        localCache.putObject(key, EXECUTION_PLACEHOLDER);
        try {
          // 执行查询
          list = doQuery(ms, parameter, rowBounds, resultHandler, boundSql);
        } finally {
          localCache.removeObject(key);
        }
        //将查询结果存入缓存中
        localCache.putObject(key, list);
        if (ms.getStatementType() == StatementType.CALLABLE) {
          localOutputParameterCache.putObject(key, parameter);
        }
        return list;
      }
    

    将处理好的sql,以及查询结果存入一级缓存中,执行查询方法;

  5. 执行SimpleExecutor的查询方法doQuery

    public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler,
    			BoundSql boundSql) throws SQLException {
    		Statement stmt = null;
    		try {
    			// 获取Configuration对象
    			Configuration configuration = ms.getConfiguration();
    			// 创建RoutingStatementHandler,用来处理Statement
    			// RoutingStatementHandler类中初始化delegate类(SimpleStatementHandler、PreparedStatementHandler)
    			StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds,
    					resultHandler, boundSql);
    			// 子流程1:设置参数
    			stmt = prepareStatement(handler, ms.getStatementLog());
    			// 子流程2:执行SQL语句(已经设置过参数),并且映射结果集
    			return handler.query(stmt, resultHandler);
    		} finally {
    			closeStatement(stmt);
    		}
    	}
    
创建Statement处理器

创建RoutingStatementHandler用来处理对应的Statement,构造方法如下;

//根据不同的类型创建不同的Statement处理器,进行处理
public RoutingStatementHandler(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {

    switch (ms.getStatementType()) {
      //简单的Statement处理器
      case STATEMENT:
        delegate = new SimpleStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
        break;
      //PreparedStatement处理器
      case PREPARED:
        delegate = new PreparedStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
        break;
      //callable处理器
      case CALLABLE:
        delegate = new CallableStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
        break;
      default:
        throw new ExecutorException("Unknown statement type: " + ms.getStatementType());
    }
  }

根据不同的类型创建不同的Statement处理器,处理statement;

  1. 设置参数,执行Statement处理器的prepareStatement方法
//后获取jdbc链接,创建Statement并设置Statement参数
private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
		Statement stmt;
		// 获取连接
		Connection connection = getConnection(statementLog);
		// 创建Statement(PreparedStatement、Statement、CallableStatement)
		stmt = handler.prepare(connection, transaction.getTimeout());
		// SQL参数设置
		handler.parameterize(stmt);
		return stmt;
	}

//创建prepareStatement
public Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException {
    ErrorContext.instance().sql(boundSql.getSql());
    Statement statement = null;
    try {
      // 实例化Statement,比如PreparedStatement
      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);
    }
  }

//创建prepareStatement
protected Statement instantiateStatement(Connection connection) throws SQLException {
	// 获取带有占位符的SQL语句
    String sql = boundSql.getSql();
    // 处理带有主键返回的SQL
    if (mappedStatement.getKeyGenerator() instanceof Jdbc3KeyGenerator) {
      String[] keyColumnNames = mappedStatement.getKeyColumns();
      if (keyColumnNames == null) {
        return connection.prepareStatement(sql, PreparedStatement.RETURN_GENERATED_KEYS);
      } else {
        return connection.prepareStatement(sql, keyColumnNames);
      }
    } else if (mappedStatement.getResultSetType() == ResultSetType.DEFAULT) {
      return connection.prepareStatement(sql);
    } else {
      return connection.prepareStatement(sql, mappedStatement.getResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY);
    }
  }

//调用prepareStatement的parameterize方法,使用parameterHandler参数处理器设置参数
public void parameterize(Statement statement) throws SQLException {
	// 通过ParameterHandler处理参数
    parameterHandler.setParameters((PreparedStatement) statement);
  }

//对prepareStatement设置参数
public void setParameters(PreparedStatement ps) {
		ErrorContext.instance().activity("setting parameters").object(mappedStatement.getParameterMap().getId());
		// 获取要设置的参数映射信息
		List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
		if (parameterMappings != null) {
			for (int i = 0; i < parameterMappings.size(); i++) {
				ParameterMapping parameterMapping = parameterMappings.get(i);
				// 只处理入参
				if (parameterMapping.getMode() != ParameterMode.OUT) {
					Object value;
					// 获取属性名称
					String propertyName = parameterMapping.getProperty();
					if (boundSql.hasAdditionalParameter(propertyName)) { // issue #448 ask first for additional params
						value = boundSql.getAdditionalParameter(propertyName);
					} else if (parameterObject == null) {
						value = null;
					} else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
						value = parameterObject;
					} else {
						MetaObject metaObject = configuration.newMetaObject(parameterObject);
						value = metaObject.getValue(propertyName);
					}
					// 获取每个参数的类型处理器,去设置入参和获取返回值
					TypeHandler typeHandler = parameterMapping.getTypeHandler();
					// 获取每个参数的JdbcType
					JdbcType jdbcType = parameterMapping.getJdbcType();
					if (value == null && jdbcType == null) {
						jdbcType = configuration.getJdbcTypeForNull();
					}
					try {
						// 给PreparedStatement设置参数
						typeHandler.setParameter(ps, i + 1, value, jdbcType);
					} catch (TypeException e) {
						throw new TypeException(
								"Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e);
					} catch (SQLException e) {
						throw new TypeException(
								"Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e);
					}
				}
			}
		}
	}

在参数处理器中创建每个参数的typeHandler(类型处理器的)setParameter方法,设置参数;

  1. 执行StatementHandler的query方法执行sql语句

    //执行PreparedStatement,也就是执行SQL语句
    public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
        PreparedStatement ps = (PreparedStatement) statement;
        // 执行PreparedStatement,也就是执行SQL语句
        ps.execute();
        // 处理结果集
        return resultSetHandler.handleResultSets(ps);
      }
    
  2. 处理结果集

    public List<Object> handleResultSets(Statement stmt) throws SQLException {
    		ErrorContext.instance().activity("handling results").object(mappedStatement.getId());
    
    		// <select>标签的resultMap属性,可以指定多个值,多个值之间用逗号(,)分割
    		final List<Object> multipleResults = new ArrayList<>();
    
    		int resultSetCount = 0;
    		// 这里是获取第一个结果集,将传统JDBC的ResultSet包装成一个包含结果列元信息的ResultSetWrapper对象
    		ResultSetWrapper rsw = getFirstResultSet(stmt);
    
    		// 这里是获取所有要映射的ResultMap(按照逗号分割出来的)
    		List<ResultMap> resultMaps = mappedStatement.getResultMaps();
    		// 要映射的ResultMap的数量
    		int resultMapCount = resultMaps.size();
    		validateResultMapsCount(rsw, resultMapCount);
    		// 循环处理每个ResultMap,从第一个开始处理
    		while (rsw != null && resultMapCount > resultSetCount) {
    			// 得到结果映射信息
    			ResultMap resultMap = resultMaps.get(resultSetCount);
    			// 处理结果集
    			// 从rsw结果集参数中获取查询结果,再根据resultMap映射信息,将查询结果映射到multipleResults中
    			handleResultSet(rsw, resultMap, multipleResults, null);
    
    			rsw = getNextResultSet(stmt);
    			cleanUpAfterHandlingResultSet();
    			resultSetCount++;
    		}
    
    		// 对应<select>标签的resultSets属性,一般不使用该属性
    		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);
    //处理结果映射
    private void handleResultSet(ResultSetWrapper rsw, ResultMap resultMap, List<Object> multipleResults,
    			ResultMapping parentMapping) throws SQLException {
    		try {
    			// 处理嵌套结果映射
    			if (parentMapping != null) {
    				handleRowValues(rsw, resultMap, null, RowBounds.DEFAULT, parentMapping);
    			} else {
    				// 第一次一般来说resultHandler为空,则创建DefaultResultHandler来处理结果
    				if (resultHandler == null) {
    					DefaultResultHandler defaultResultHandler = new DefaultResultHandler(objectFactory);
    					// 处理行数据,其实就是完成结果映射
    					handleRowValues(rsw, resultMap, defaultResultHandler, rowBounds, null);
    
    					multipleResults.add(defaultResultHandler.getResultList());
    				} else {
    					handleRowValues(rsw, resultMap, resultHandler, rowBounds, null);
    				}
    			}
    		} finally {
    			// issue #228 (close resultsets)
    			closeResultSet(rsw.getResultSet());
    		}
    	}
    
    //判断映射嵌套关系
    public void handleRowValues(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler,
    			RowBounds rowBounds, ResultMapping parentMapping) throws SQLException {
    		// 是否有内置嵌套的结果映射
    		if (resultMap.hasNestedResultMaps()) {
    			ensureNoRowBounds();
    			checkResultHandler();
    			// 嵌套结果映射
    			handleRowValuesForNestedResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);
    		} else {
    			// 简单结果映射
    			handleRowValuesForSimpleResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);
    		}
    }
    
    //处理简单的映射关系
    private void handleRowValuesForSimpleResultMap(ResultSetWrapper rsw, ResultMap resultMap,
    			ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping) throws SQLException {
    		DefaultResultContext<Object> resultContext = new DefaultResultContext<>();
    		// 获取结果集信息
    		ResultSet resultSet = rsw.getResultSet();
    		// 使用rowBounds的分页信息,进行逻辑分页(也就是在内存中分页)
    		skipRows(resultSet, rowBounds);
    		while (shouldProcessMoreRows(resultContext, rowBounds) && !resultSet.isClosed() && resultSet.next()) {
    			// 通过<resultMap>标签的子标签<discriminator>对结果映射进行鉴别
    			ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(resultSet, resultMap, null);
    			// 将查询结果封装到POJO中
    			Object rowValue = getRowValue(rsw, discriminatedResultMap, null);
    			// 处理对象嵌套的映射关系
    			storeObject(resultHandler, resultContext, rowValue, parentMapping, resultSet);
    		}
    }
    
    

    处理完成后,将查询到的结果返回;

    到这里我们完整的走了一遍Mybatis通过接口Mapper映射文件查询数据库,经过了解析xml、封装SQl、获取SQl、执行SQl、解析结果集。希望通过学习源码让自己对框架的了解更深一些.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值