Mybatis源码之Sql执行

原文地址 https://www.jianshu.com/p/937a797d5d11

获取 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.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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值