2.10、mybatis源码分析之sql执行过程以select为例

  • 在研究select执行过程之前先来介绍一个重要的类

一、SqlNode和SqlSource

  • 在myabtis初始化过程中可以知道,映射配置文件中的sql节点会被解析为MappedStatement对象,其中sql语句解析成SqlSource对象,sql语句中定义的Sql节点、文本节点等,则由SqlNode接口的响应实现。

1、SqlSource接口

SqlSource接口结构
public interface SqlSource {
//通过解析得到BoundSql对象,其中封装了包含?占位符号的sql语句以及绑定的实参
  BoundSql getBoundSql(Object parameterObject);
}

2、SqlNode

public interface SqlNode {
//根据用户传入的实际参数,解析该sqlNode所记录的动态的sql节点,当sql节点下的所有sqlnode
//完成解析后,我们就可以从dynamicContext中获取一条动态生成的完整的sql语句。
  boolean apply(DynamicContext context);
}
  • sqlNode有很多的实现类,比如ChooseSqlNode、ForEachSqlNode等

二、StatementHandler

  • 核心接口,完成mybatis中最核心的工作,接口功能很多,例如创建statement对象,为sql语句绑定实际参数,执行select、insert等多种类型的sql语句,并将结果集映射成结果对象。


    StatementHandler类结构图

1、RoutingStatementHandler

  • 很根据MapperdStatement中指定的statementType字段,创建相应的StatementHandler接口实现。

2、BaseStatementHandler

  • 实现了Statementhandler接口的抽象类,只提供了参数绑定的相关方法,并没有具体操作数据库的方法。依赖于ParameterHandler和ResultSetHandler组件
  • 实现了 StatementHandler接口中的prepare方法,该方法中调用instantiateStatement抽象方法初始化statement对象,然后配置相关的参数

3、PreparedStatementHandler等

  • 是BaseStatementHandler的实现类,是具体操作sql的地方

三、ResultHandler

  • StatementHandler接口在执行完指定的select语句之后,会将查询得到的结果集交给ResultSetHandler完成映射处理,ResultSetHandler除了负责映射select语句得到的结果集还会处理存储过程执行后的输出参数
public interface ResultSetHandler {
//处理结果集生成相应的结果对象集合
   List handleResultSets(Statement stmt) throws SQLException;
//处理结果集,返回相应的游标对象
   Cursor handleCursorResultSets(Statement stmt) throws SQLException;
//处理存储过程的输出对象
  void handleOutputParameters(CallableStatement cs) throws SQLException;

}

1、DefaultResultSetHandler实现类

  • 重要的属性:
 private final Executor executor;
  private final Configuration configuration;
  private final MappedStatement mappedStatement;
  private final RowBounds rowBounds;
  private final ParameterHandler parameterHandler;
//用户指定用于处理结果的ResultHandler对象
  private final ResultHandler resultHandler;
  private final BoundSql boundSql;
  private final TypeHandlerRegistry typeHandlerRegistry;
  private final ObjectFactory objectFactory;
  private final ReflectorFactory reflectorFactory;

四、select的执行流程

1、方法入口,执行代理接口的invoke方法

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  //判断方法的父类是否是Object如果是就直接调用
    if (Object.class.equals(method.getDeclaringClass())) {
      return method.invoke(this, args);
    }
    //获取MapperMethod并缓存
    final MapperMethod mapperMethod = cachedMapperMethod(method);
    return mapperMethod.execute(sqlSession, args);
  }
   private final Map methodCache;
1、获取MapperMethod时候先判断methodCache有没有,没有的话那么直接创建然后放入methodCache中(下次调用直接从map中获取)
  private MapperMethod cachedMapperMethod(Method method) {
    MapperMethod mapperMethod = methodCache.get(method);
    if (mapperMethod == null) {
    //构建mapperMethod方法
      mapperMethod = new MapperMethod(mapperInterface, method, sqlSession.getConfiguration());
      methodCache.put(method, mapperMethod);
    }
    return mapperMethod;
  }
2、创建MapperMethod对象,SqlCommand和MethodSignature是MapperMethod的内部类
   public MapperMethod(Class mapperInterface, Method method, Configuration config) {
     //SqlCommand包含了mapper.xml文件中的相关sql语句及属性信息
    this.command = new SqlCommand(config, mapperInterface, method);
    //MethodSignature包含了mapper接口方法签名的信息
    this.method = new MethodSignature(config, method);
  }
2.1、获取SqlCommand
   public SqlCommand(Configuration configuration, Class declaringInterface, Method method) throws BindingException {
     //包名+方法名作为唯一的id
      name = declaringInterface.getName() + "." + method.getName();
      final MappedStatement ms;
      try {
        //根据id获取
        ms = configuration.getMappedStatement(name);
      } catch (Exception e) {
        throw new BindingException("Invalid bound statement (not found): " + name, e);
      }
      //获取crud类型如果是unknown就报错误
      type = ms.getSqlCommandType();
      if (type == SqlCommandType.UNKNOWN) {
        throw new BindingException("Unknown execution method for: " + name);
      }
    }
2.2、获取MethodSignature
 public MethodSignature(Configuration configuration, Class mapperInterface, Method method) {
      Type resolvedReturnType = TypeParameterResolver.resolveReturnType(method, mapperInterface);
      if (resolvedReturnType instanceof Class) {
        this.returnType = (Class) resolvedReturnType;
      } else if (resolvedReturnType instanceof ParameterizedType) {
        this.returnType = (Class) ((ParameterizedType) resolvedReturnType).getRawType();
      } else {
        this.returnType = method.getReturnType();
      }
      this.returnsVoid = void.class.equals(this.returnType);
      this.returnsMany = configuration.getObjectFactory().isCollection(this.returnType) || this.returnType.isArray();
      this.returnsCursor = Cursor.class.equals(this.returnType);
      this.mapKey = getMapKey(method);
      this.returnsMap = this.mapKey != null;
      this.rowBoundsIndex = getUniqueParamIndex(method, RowBounds.class);
      this.resultHandlerIndex = getUniqueParamIndex(method, ResultHandler.class);
      this.paramNameResolver = new ParamNameResolver(configuration, method);
    }

2、执行MapperMethod的execute方法

public Object execute(SqlSession sqlSession, Object[] args) {
    Object result;
    //根据SqlCommand类型判断是执行curd的哪一个
    //insert
    if (SqlCommandType.INSERT == command.getType()) {
        //将参数转换为sql命令的参数
      Object param = method.convertArgsToSqlCommandParam(args);
      result = rowCountResult(sqlSession.insert(command.getName(), param));
      //update
    } else if (SqlCommandType.UPDATE == command.getType()) {
      Object param = method.convertArgsToSqlCommandParam(args);
      result = rowCountResult(sqlSession.update(command.getName(), param));
      //delete
    } else if (SqlCommandType.DELETE == command.getType()) {
      Object param = method.convertArgsToSqlCommandParam(args);
      result = rowCountResult(sqlSession.delete(command.getName(), param));
      //select
    } else if (SqlCommandType.SELECT == command.getType()) {
    //MethodSignature方法签名的返回类型来进行不同的逻辑处理
      if (method.returnsVoid() && method.hasResultHandler()) {
        executeWithResultHandler(sqlSession, args);
        result = null;
      } else if (method.returnsMany()) {
        result = executeForMany(sqlSession, args);
      } else if (method.returnsMap()) {
        result = executeForMap(sqlSession, args);
      } else {
      //当不满足上面需求的时候进行这一步操作,先进行参数解析,包装为map返回
        Object param = method.convertArgsToSqlCommandParam(args);
        result = sqlSession.selectOne(command.getName(), param);
      }
    } else {
      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;
  }  

3、DefaultSqlSession中执行sqlSession.selectOne方法

public  T selectOne(String statement, Object parameter) {
    // 调用selectList获取list列表,然后获取第一个。如果有多个那么就直接报错误
    List 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;
    }
  }

4、归根结底还是调用executor的query方法来执行

public  List selectList(String statement, Object parameter, RowBounds rowBounds) {
    try {
        ////根据statementId获取MappedStatement,MappedStatement封装了增删改查的详细信息
      MappedStatement ms = configuration.getMappedStatement(statement);
      //调用executor的query
      List result = executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
      return result;
    } catch (Exception e) {
      throw ExceptionFactory.wrapException("Error querying database.  Cause: " + e, e);
    } finally {
      ErrorContext.instance().reset();
    }
  }
//包装参数为map类型
  private Object wrapCollection(final Object object) {
    if (object instanceof List) {
      StrictMap map = new StrictMap();
      map.put("list", object);
      return map;
    } else if (object != null && object.getClass().isArray()) {
      StrictMap map = new StrictMap();
      map.put("array", object);
      return map;
    }
    return object;
  }
 
 

5、执行cachingExecutor的query方法,

public  List query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
    //获取解析过动态标签的sql,BoundSql包含当前sql语句的详细信息和参数
    BoundSql boundSql = ms.getBoundSql(parameterObject);
    //创建缓存key
    CacheKey key = createCacheKey(ms, parameterObject, rowBounds, boundSql);
    return query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
  }

6、获取BoundSql

public BoundSql getBoundSql(Object parameterObject) {
/*获取解析过动态标签的sql*/
    BoundSql boundSql = sqlSource.getBoundSql(parameterObject);
    List parameterMappings = boundSql.getParameterMappings();
    if (parameterMappings == null || parameterMappings.size() <= 0) {
      boundSql = new BoundSql(configuration, boundSql.getSql(), parameterMap.getParameterMappings(), parameterObject);
    }

    // 检查参数映射中是否存在嵌套的resultMap并设置boolean标记
    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;
  }

7、执行BaseExecutor的query

public  List 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, key, parameterObject, boundSql);
        if (!dirty) {
          cache.getReadWriteLock().readLock().lock();
          try {
            @SuppressWarnings("unchecked")
            List cachedList = (List) cache.getObject(key);
            if (cachedList != null) return cachedList;
          } finally {
            cache.getReadWriteLock().readLock().unlock();
          }
        }
        List list = delegate. query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
        tcm.putObject(cache, key, list); // issue #578. Query must be not synchronized to prevent deadlocks
        return list;
      }
    }
    return delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
  }

public  List 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 list;
    try {
      queryStack++;
      list = resultHandler == null ? (List) 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();
      }
      deferredLoads.clear(); // issue #601
      if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {
        clearLocalCache(); // issue #482
      }
    }
    return list;
  }
  
private  List queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
    List list;
    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;
  }

8、这里在SimpleExecutor中真正的执行query(根据配置还可以在选择其他的Executor)

 public  List doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
    Statement stmt = null;
    try {
      Configuration configuration = ms.getConfiguration();
     //创建statementhandler,statementhandler是创建原生statement的处理器
      StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, rowBounds, resultHandler, boundSql);
     //准备Statement
      stmt = prepareStatement(handler, ms.getStatementLog());
      return handler.query(stmt, resultHandler);
    } finally {
      closeStatement(stmt);
    }
  }

9、构建StatementHandler

 public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
   /*构造RoutingStatementHandler*/
    StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql);
   //拦截器执行
    statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler);
    return statementHandler;
  }
  //终于柳暗花明了
  public RoutingStatementHandler(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
//根据MappedStatement中的statement类型来创建响应的statement处理器
    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());
    }

  }

10、statement的准备

  private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
    Statement stmt;
    //获取数据库连接
    Connection connection = getConnection(statementLog);
    //进行响应的statement的转呗工作
    stmt = handler.prepare(connection);
    //给statement设置参数
    handler.parameterize(stmt);
    return stmt;
  }
public Statement prepare(Connection connection) throws SQLException {
    ErrorContext.instance().sql(boundSql.getSql());
    Statement statement = null;
    try {
    //实例化对象的statement
      statement = instantiateStatement(connection);
      //设置超时时间
      setStatementTimeout(statement);
      //设置FetchSize
      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);
    }
  }
实例化过程以预处理statement为例:
  protected Statement instantiateStatement(Connection connection) throws SQLException {
    String sql = boundSql.getSql();
    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() != null) {
      return connection.prepareStatement(sql, mappedStatement.getResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY);
    } else {
      return connection.prepareStatement(sql);
    }
  }

11、设置参数过程

public void setParameters(PreparedStatement ps) {
    ErrorContext.instance().activity("setting parameters").object(mappedStatement.getParameterMap().getId());
    List 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)) {
                    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);
                }
            }
        }
    }
}

12、最后执行查询并进行参数封装

  public  List query(Statement statement, ResultHandler resultHandler) throws SQLException {
    PreparedStatement ps = (PreparedStatement) statement;
    //执行sql语句
    ps.execute();
    //参数封装
    return resultSetHandler. handleResultSets(ps);
  }
select执行流程

你可能感兴趣的:(2.10、mybatis源码分析之sql执行过程以select为例)