美文网首页
Mybatis源码之Sql执行

Mybatis源码之Sql执行

作者: Kohler | 来源:发表于2018-08-06 16:53 被阅读25次

获取SqlSession

mapper解析完毕后,整个configuration就算解析完成,根据sqlSessionFactory获取session,然后获取mapper执行sql

SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession sqlSession = sqlSessionFactory.openSession();

openSession()方法调用重载方法

//DefaultSqlSessionFactory
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
  Transaction tx = null;
  try {
    final Environment environment = configuration.getEnvironment();
      // JdbcTransactionFactory
    final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
      // JdbcTransaction
    tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
      // CachingExecutor、
    final Executor executor = configuration.newExecutor(tx, execType);
    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();
  }
}

返回创建DefaultSqlSession

获取Mapper

BlogDao blogDao = sqlSession.getMapper(BlogDao.class);

从已解析的结果集合中取出对应的MapperProxyFactory,创建相应的代理

public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
  final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
  if (mapperProxyFactory == null) {
    throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
  }
  try {
    return mapperProxyFactory.newInstance(sqlSession);
  } catch (Exception e) {
    throw new BindingException("Error getting mapper instance. Cause: " + e, e);
  }
}

通过mapperProxyFactory来创建MapperProxy代理类,代码如下

public T newInstance(SqlSession sqlSession) {
  final MapperProxy<T> mapperProxy = new MapperProxy<T>(sqlSession, mapperInterface, methodCache);
  return newInstance(mapperProxy);
}
protected T newInstance(MapperProxy<T> mapperProxy) {
  return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
}

MapperProxy实现了InvocationHandler接口,也就是说获取的Mapper对象方法调用最后会调用MapperProxy.invoke()

执行SQL

调用MapperProxy.invoke()方法

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);
  }
  final MapperMethod mapperMethod = cachedMapperMethod(method);
  return mapperMethod.execute(sqlSession, args);
}

如果是Object类的方法或者default方法直接执行,其它方法 执行mapperMethod.execute(),execute方法根据类型执行相应的语句

  1. INSERT -> sqlSession.insert
  2. UPDATE -> sqlSession.update
  3. DELETE-> sqlSession.delete
  4. SELECT-> sqlSession.select*
  5. FLUSH-> sqlSession.flushStatements

select 方法 有多种,需要进行结果集映射,以executeForMany(sqlSession, args)为例来看,方法会调用sqlSession.<E>selectList()

// DefaultSqlSession.selectList
public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
    MappedStatement ms = configuration.getMappedStatement(statement);
    return executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
}

// CachingExecutor.query
public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
    BoundSql boundSql = ms.getBoundSql(parameterObject);
    CacheKey key = createCacheKey(ms, parameterObject, rowBounds, boundSql);
    return query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}

boundSql中包含之中要执行的sql,getBoundSql方法会通过SqlSource来获取 ,这里的sqlSource为之前解析的,存在两种:DynamicSqlSource,RawSqlSource。

  1. RawSqlSource相比DynamicSqlSource就简单多了,在创建RawSqlSource时直接就将sql解析了,直接获取即可。
  2. 动态sql会在执行时解析并转化为静态sql

调用query方法,这里调用的虽然是CachingExecutor类,但最后会委派给SimpleExecutor调用,调用会访问cache,并把结果放在cache中

@Override
public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
  Statement stmt = null;
  try {
    Configuration configuration = ms.getConfiguration();
    StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
      // 这里才开始获取连接
    stmt = prepareStatement(handler, ms.getStatementLog());
    return handler.<E>query(stmt, resultHandler);
  } finally {
    closeStatement(stmt);
  }
}

@Override
public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
String sql = boundSql.getSql();
statement.execute(sql);
return resultSetHandler.<E>handleResultSets(statement);
}

结果映射

在处理结果集行值时分为两部分,处理简单resultMap对应的行值和处理嵌套resultMap对应的行值,是否嵌套映射在解析mapper resultMap的时候已经解释过了,这里不再重复。处理简单resultMap对应的行值稍微简单些,先看简单的映射

private void handleRowValuesForSimpleResultMap(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping)
    throws SQLException {
  DefaultResultContext<Object> resultContext = new DefaultResultContext<Object>();
    //处理分页,跳过指定的行,如果rs类型不是TYPE_FORWARD_ONLY,直接absolute,否则的话循环rs.next
  skipRows(rsw.getResultSet(), rowBounds);
  while (shouldProcessMoreRows(resultContext, rowBounds) && rsw.getResultSet().next()) {
    ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(rsw.getResultSet(), resultMap, null);
      //处理行值,重点分析
    Object rowValue = getRowValue(rsw, discriminatedResultMap);
      //保存对象,通过list保存生成的对象Object
    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;
}

获取行值主要包含如下3个步骤:

  1. createResultObject()方法创建结果集对象
    根据resultType,通过ObjectFactory.create来创建对象,其实现原理还是通过反射来创建对象。在创建对象时如果resultMap未配置constructor,通过默认构造方法来创建对象,否则通过有参的构造方法来创建对象

  2. 自动映射属性
    applyAutomaticMappings(),如果ResultMap配置了autoMapping="true",或者AutoMappingBehavior为PARTIAL会自动映射在resultSet查询列中存在但是未在resultMap中配置的列。

  3. 人工映射属性
    映射在resultMap中配置的列,主要包括两步:获取属性的值和设置属性的值。

    //获取属性的值
    Object value = getPropertyMappingValue(rsw.getResultSet(), metaObject, propertyMapping, lazyLoader, columnPrefix);
    //设置属性的值,通过反射来设置
    metaObject.setValue(property, value);
    
    private Object getPropertyMappingValue(ResultSet rs, MetaObject metaResultObject, ResultMapping propertyMapping, ResultLoaderMap lazyLoader, String columnPrefix)
        throws SQLException {
        //获取嵌套查询对应的属性值,最终还是通过Executor.query来获取属性值
      if (propertyMapping.getNestedQueryId() != null) {
        return getNestedQueryMappingValue(rs, metaResultObject, propertyMapping, lazyLoader, columnPrefix);
      } else if (propertyMapping.getResultSet() != null) {
        addPendingChildRelation(rs, metaResultObject, propertyMapping);   // TODO is that OK?
        return DEFERED;
      } else {
        final TypeHandler<?> typeHandler = propertyMapping.getTypeHandler();
        final String column = prependPrefix(propertyMapping.getColumn(), columnPrefix);
          //通过typeHandler来获取属性的值,如StringTypeHandler获取属性值:rs.getString(columnName)
        return typeHandler.getResult(rs, column);
      }
    }
    

嵌套映射

嵌套resultMap主要用来处理collection,association属性

<resultMap id="detailedBlogResultMap" type="Blog">
    <result property="id" column="id"/>
    <result property="title" column="title"/>
    <result property="content" column="content"/>

    <association property="author" javaType="com.zero.mybatis.bean.Author">
        <id property="id" column="author"/>
        <id property="name" column="name"/>
        <id property="age" column="age"/>
    </association>
</resultMap>

<!--alias Blog-->
<select id="selectBlog" resultMap="detailedBlogResultMap">
    select * from blog join author on blog.author = author.id where blog.id = 1;
</select>

Blog有一个author属性,代表Author的id

处理嵌套映射主要包括如下几个步骤:

  1. skipRows(rsw.getResultSet(), rowBounds); 同简单映射
  2. createRowKey,根据resultMap下的列创建rowKey,很有用。在如上liveCourseMap配置中,mybatis将会根据id列和course_name列的值来创建rowKey
  3. getRowValue

在handleRowValues()方法中,if条件成立进入handleRowValuesForNestedResultMap()方法

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 handleRowValuesForNestedResultMap(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping) throws SQLException {
    final DefaultResultContext<Object> resultContext = new DefaultResultContext<Object>();
    skipRows(rsw.getResultSet(), rowBounds);
    Object rowValue = previousRowValue;
    while (shouldProcessMoreRows(resultContext, rowBounds) && rsw.getResultSet().next()) {
      final ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(rsw.getResultSet(), resultMap, null);
        //创建rowKey,根据rowKey判断对象创建没创建
      final CacheKey rowKey = createRowKey(discriminatedResultMap, rsw, null);
        //已经创建的对象会保存到nestedResultObjects
      Object partialObject = nestedResultObjects.get(rowKey);
      // issue #577 && #542
      if (mappedStatement.isResultOrdered()) {
        if (partialObject == null && rowValue != null) {
          nestedResultObjects.clear();
          storeObject(resultHandler, resultContext, rowValue, parentMapping, rsw.getResultSet());
        }
        rowValue = getRowValue(rsw, discriminatedResultMap, rowKey, null, partialObject);
      } else {
        rowValue = getRowValue(rsw, discriminatedResultMap, rowKey, null, partialObject);
        if (partialObject == null) {
          storeObject(resultHandler, resultContext, rowValue, parentMapping, rsw.getResultSet());
        }
      }
    }
    if (rowValue != null && mappedStatement.isResultOrdered() && shouldProcessMoreRows(resultContext, rowBounds)) {
      storeObject(resultHandler, resultContext, rowValue, parentMapping, rsw.getResultSet());
      previousRowValue = null;
    } else if (rowValue != null) {
      previousRowValue = rowValue;
    }
  }

getRowValue()方法

private Object getRowValue(ResultSetWrapper rsw, ResultMap resultMap, CacheKey combinedKey, String columnPrefix, Object partialObject) throws SQLException {
  final String resultMapId = resultMap.getId();
  Object rowValue = partialObject;
  if (rowValue != null) {
    final MetaObject metaObject = configuration.newMetaObject(rowValue);
    putAncestor(rowValue, resultMapId);
    applyNestedResultMappings(rsw, resultMap, metaObject, columnPrefix, combinedKey, false);
    ancestorObjects.remove(resultMapId);
  } else {
    final ResultLoaderMap lazyLoader = new ResultLoaderMap();
      // 创建外部对象
    rowValue = createResultObject(rsw, resultMap, lazyLoader, columnPrefix);
    if (rowValue != null && !hasTypeHandlerForResultObject(rsw, resultMap.getType())) {
      final MetaObject metaObject = configuration.newMetaObject(rowValue);
      boolean foundValues = this.useConstructorMappings;
      if (shouldApplyAutomaticMappings(resultMap, true)) {
          //自动映射
        foundValues = applyAutomaticMappings(rsw, resultMap, metaObject, columnPrefix) || foundValues;
      }
      foundValues = applyPropertyMappings(rsw, resultMap, metaObject, lazyLoader, columnPrefix) || foundValues;
      putAncestor(rowValue, resultMapId);
        //嵌套映射
      foundValues = applyNestedResultMappings(rsw, resultMap, metaObject, columnPrefix, combinedKey, true) || foundValues;
      ancestorObjects.remove(resultMapId);
      foundValues = lazyLoader.size() > 0 || foundValues;
      rowValue = foundValues || configuration.isReturnInstanceForEmptyRow() ? rowValue : null;
    }
    if (combinedKey != CacheKey.NULL_CACHE_KEY) {
      nestedResultObjects.put(combinedKey, rowValue);
    }
  }
  return rowValue;
}

相关文章

网友评论

      本文标题:Mybatis源码之Sql执行

      本文链接:https://www.haomeiwen.com/subject/ppygvftx.html