前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Mybatis之ResultSetHandler

Mybatis之ResultSetHandler

作者头像
克虏伯
修改2019-10-22 10:27:48
1.4K0
修改2019-10-22 10:27:48
举报
文章被收录于专栏:软件开发-青出于蓝

    mybatis-3.4.6.release.

    ResultSetHandler是个接口,如List-1

List-1

代码语言:javascript
复制
public interface ResultSetHandler {
  //将结果转换为List
  <E> List<E> handleResultSets(Statement stmt) throws SQLException;
  //将结果转换为游标Cursor
  <E> Cursor<E> handleCursorResultSets(Statement stmt) throws SQLException;

  void handleOutputParameters(CallableStatement cs) throws SQLException;
}

    实现类只有DefaultResultSetHandler,实现有点复杂,因为要考虑的情况很多。

    结果封装原理

List-2

代码语言:javascript
复制
<resultMap type="Person" id="resultPersonMap">
    <result property="id" column="id"/>
    <result property="username" column="username"/>
    <result property="password" column="password"/>
    <result property="fltNum" column="flt_num"/>
</resultMap>

    如List-2, 定义这样一个ResultMap后,使用ObjectFactory创建一个Person对象,

person.setId(resultSet.getInt("id"))

person.setUsername(resultSet.getString("username"))

person.setPassword(resultSet.getString("password"))

person.setFltNum(resultSet.getString("flt_num"))

    不过这个转换过程在实现上很复杂,其中就用到TypeHandler。

    开始之前,来看下ResultSetWrapper,如下List-3,通过ResultSet获取ResultSetMetaData来获取列的属性,遍历列,获取列名称、列类型、对应的JdbcType。

List-3

代码语言:javascript
复制
public ResultSetWrapper(ResultSet rs, Configuration configuration) throws SQLException {
    super();
    this.typeHandlerRegistry = configuration.getTypeHandlerRegistry();
    this.resultSet = rs;
    final ResultSetMetaData metaData = rs.getMetaData();
    final int columnCount = metaData.getColumnCount();
    for (int i = 1; i <= columnCount; i++) {
        columnNames.add(configuration.isUseColumnLabel() ? metaData.getColumnLabel(i) : metaData.getColumnName(i));
        jdbcTypes.add(JdbcType.forCode(metaData.getColumnType(i)));
        classNames.add(metaData.getColumnClassName(i));
    }
}

    来看DefaultResultSetHandler的handleResultSets方法,

List-4

代码语言:javascript
复制
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;
    ResultSetWrapper rsw = getFirstResultSet(stmt);//1

    List<ResultMap> resultMaps = mappedStatement.getResultMaps();//2
    int resultMapCount = resultMaps.size();
    validateResultMapsCount(rsw, resultMapCount);//3
    while (rsw != null && resultMapCount > resultSetCount) {
        ResultMap resultMap = resultMaps.get(resultSetCount);//4
        handleResultSet(rsw, resultMap, multipleResults, null);//5
        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);
}

1处通过ResultSetMetadata获取列的属性

2处获取我们定义的resultMap,如List-2

3处验证resultMap个数,如果小于1则会报错

4处获取resultMap,从List中

5处是核心,调用handleResultSet->handleRowValues->handleRowValuesForSimpleResultMap

List-5

代码语言:javascript
复制
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()) {
        ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(rsw.getResultSet(), resultMap, null);
        Object rowValue = getRowValue(rsw, discriminatedResultMap);//1
        storeObject(resultHandler, resultContext, rowValue, parentMapping, rsw.getResultSet());
    }
}

    handleRowValuesForSimpleResultMap方法中,不断调用resultSet.next()方法,会获取resultSet中的所有数据。

    List-5的1处,调用getRowValue方法,该方法获取resultSet中的一行数据,并将数据封装位对象

List-6

代码语言:javascript
复制
private Object getRowValue(ResultSetWrapper rsw, ResultMap resultMap) throws SQLException {
    final ResultLoaderMap lazyLoader = new ResultLoaderMap();
    Object rowValue = createResultObject(rsw, resultMap, lazyLoader, null);//1
    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;//2
        }
        foundValues = applyPropertyMappings(rsw, resultMap, metaObject, lazyLoader, null) || foundValues;
        foundValues = lazyLoader.size() > 0 || foundValues;
        rowValue = foundValues || configuration.isReturnInstanceForEmptyRow() ? rowValue : null;
    }
    return rowValue;
}

    List-6中1处,通过反射,创建Person对象(如List-7),之后在List-6的2处

List-7

代码语言:javascript
复制
<select id="findByUsername" resultType="Person" parameterType="Person">
    select * from person where username=#{username};
</select>

List-8

代码语言:javascript
复制
private boolean applyAutomaticMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject, String columnPrefix) throws SQLException {
    List<UnMappedColumnAutoMapping> autoMapping = createAutomaticMappings(rsw, resultMap, metaObject, columnPrefix);
    boolean foundValues = false;
    if (!autoMapping.isEmpty()) {
        for (UnMappedColumnAutoMapping mapping : autoMapping) {
        final Object value = mapping.typeHandler.getResult(rsw.getResultSet(), mapping.column);
        if (value != null) {
            foundValues = true;
        }
        if (value != null || (configuration.isCallSettersOnNulls() && !mapping.primitive)) {
            // gcode issue #377, call setter on nulls (value is not 'found')
            metaObject.setValue(mapping.property, value);
        }
        }
    }
    return foundValues;
}

    List-8中,createAutomaticMappings方法返还sql查询的列属性——从ResultSetWrapper中获取的,之后遍历这些列,对每一列,都调用typeHandler.getResult方法获取值,之后用metaObject.setValue,内部通过反射的方式设置值。这样createAutomaticMappings方法执行完成后,就获取了resultSet中的一行数据,且封装到对象中了。

    回到List-5中,getRowValue方法返回值,storeObject方法中将值放入到List中。

    描述较为泛华,建议个人阅读源码。此外,比如懒加载在ResultSetHandler中实现。

Reference

  1. https://github.com/mybatis/mybatis-3/tree/3.4.x
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Reference
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档