mybatis原理:结果集封装详解 您所在的位置:网站首页 结果集封装 mybatis原理:结果集封装详解

mybatis原理:结果集封装详解

#mybatis原理:结果集封装详解| 来源: 网络整理| 查看: 265

        经过sql参数解析、sql动态组装和执行sql,相对而言,结果集的封装,是mybatis数据处理的最后一环。这里只对查询结果而言,因为更新语句一般都是返回影响的行数。抛开mybatis,如果让我们组装结果,我们该如何进行呢?mybatis的查询结果统一表示为:

List

即使是查询单个对象,它的查询结果还是封装成 List 对象,然后返回list集合的第一个元素。

个人根据mybatis的源码,将mybatis对结果集的封装,分成两步:

(1)通过反射,创建结果对象,其所有属性为默认值,例如,如果结果是实体对象,那么将通过无参构造函数创建对象,其所有属性一般为空,如果结果是List,则会创建一个空的List (2)为结果对象的属性赋值,这里也是通过反射,找到set方法赋值

 

下面开始进入主题:

一、数据准备

1. 查询sql以及自定义映射的resultMap:

select u.id,u.username,u.password,u.is_valid,b.id as blog_id,b.title,b.user_id from t_user u LEFT JOIN t_blog b ON u.id = b.user_id where u.id=#{id}

从查询sql,你也可以发现一二,比如博客表t_blog中,含有一个逻辑外键user_id,表示该博客属于哪个用户的,而每个用户可以拥有多个博客,显然是一对多的关系,而查询条件则为用户id。

 

2.实体类

public class User implements Serializable{ private String id; private String username; private String password; private Integer isValid; //一个用户,对应多篇博客 private List blogs; } public class Blog implements Serializable{ private String id; private String title; private String userId; }

3.mapper接口

public interface UserMapper { //根据id查询用户及其所有博客 User getUserAndBlogByUserId(String id); }

4.测试方法

public class One2ManyQuery { public static void main(String[] args) throws IOException { //读取配置信息 InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml"); //根据配置信息,创建SqlSession工厂 SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream); //SqlSession工厂创建SqlSession SqlSession sqlSession = factory.openSession(); //获取接口的代理对象 UserMapper mapper = sqlSession.getMapper(UserMapper.class); User user = mapper.getUserAndBlogByUserId("123"); System.out.println(user); } }

 

二、结果对象的创建

        本次程序的起点是PreparedStatementHandler的方法,它是查询的结束,同时也是结果封装的开始入口:

@Override public List query(Statement statement, ResultHandler resultHandler) throws SQLException { PreparedStatement ps = (PreparedStatement) statement; ps.execute(); return resultSetHandler.handleResultSets(ps); }

        由此,进入到 resultSetHandler.handleResultSets(ps) 方法,而默认会进入到的DefaultResultSetHandler的handleResultSets方法:

@Override public List handleResultSets(Statement stmt) throws SQLException { ErrorContext.instance().activity("handling results").object(mappedStatement.getId()); // 要返回的结果 final List multipleResults = new ArrayList(); // 迭代变量,结果集的个数 int resultSetCount = 0; // 获取第一个结果集,并包装成ResultSetWrapper对象, // ResultSetWrapper对象含有已映射和未映射的列名和属性的对应关系 ResultSetWrapper rsw = getFirstResultSet(stmt); // 获取所有的ResultMap List resultMaps = mappedStatement.getResultMaps(); // ResultMap的个数 int resultMapCount = resultMaps.size(); // 校验:如果结果集有数据,但是没有定义返回的结果类型,就会报错 validateResultMapsCount(rsw, resultMapCount); while (rsw != null && resultMapCount > resultSetCount) { // 依次获取ResultMap ResultMap resultMap = resultMaps.get(resultSetCount); // 处理结果集,这里是重点 handleResultSet(rsw, resultMap, multipleResults, null); // 获取下一个结果集 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); }

那么,我们重点关注一下这句,因为它才是真正的处理结果集:

// 处理结果集,这里是重点 handleResultSet(rsw, resultMap, multipleResults, null); private void handleResultSet(ResultSetWrapper rsw, ResultMap resultMap, List multipleResults, ResultMapping parentMapping) throws SQLException { try { if (parentMapping != null) { handleRowValues(rsw, resultMap, null, RowBounds.DEFAULT, parentMapping); } else { if (resultHandler == null) { // 如果结果处理器为空,则使用默认的结果处理器,没有自定义的情况下,都是走这个流程 DefaultResultHandler defaultResultHandler = new DefaultResultHandler(objectFactory); // 处理每一行的值 handleRowValues(rsw, resultMap, defaultResultHandler, rowBounds, null); // 将处理结果放到list集中 multipleResults.add(defaultResultHandler.getResultList()); } else { handleRowValues(rsw, resultMap, resultHandler, rowBounds, null); } } } finally { // issue #228 (close resultsets) closeResultSet(rsw.getResultSet()); } }

根据上面的代码,我们关注这一句代码是如何处理的:

// 处理每一行的值 handleRowValues(rsw, resultMap, defaultResultHandler, rowBounds, null);

查看详细的 handleRowValues 方法:

public void handleRowValues(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler resultHandler, RowBounds rowBounds, ResultMapping parentMapping) throws SQLException { // 如果有嵌套的ResultMap if (resultMap.hasNestedResultMaps()) { ensureNoRowBounds(); checkResultHandler(); // 处理含有嵌套ResultMap的结果 handleRowValuesForNestedResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping); } else { // 处理不含有嵌套ResultMap的结果 handleRowValuesForSimpleResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping); } }

      由于我们使用了 collection 标签做一对多的映射,所以是属于嵌套的resultMap查询,个人理解,即使是一个实体对象,它也是一个resultMap,只不过它的resultType是实体对象罢了,所以走的嵌套分支:

// 处理含有嵌套ResultMap的结果 handleRowValuesForNestedResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);

这个方法比较长:

private void handleRowValuesForNestedResultMap(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler resultHandler, RowBounds rowBounds, ResultMapping parentMapping) throws SQLException { final DefaultResultContext resultContext = new DefaultResultContext(); ResultSet resultSet = rsw.getResultSet(); // 跳过已处理的行 skipRows(resultSet, rowBounds); Object rowValue = previousRowValue; while (shouldProcessMoreRows(resultContext, rowBounds) && !resultSet.isClosed() && resultSet.next()) { final ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(resultSet, resultMap, null); final CacheKey rowKey = createRowKey(discriminatedResultMap, rsw, null); Object partialObject = nestedResultObjects.get(rowKey); // issue #577 && #542 if (mappedStatement.isResultOrdered()) { if (partialObject == null && rowValue != null) { nestedResultObjects.clear(); storeObject(resultHandler, resultContext, rowValue, parentMapping, resultSet); } rowValue = getRowValue(rsw, discriminatedResultMap, rowKey, null, partialObject); } else { // 看这行代码,获取行值 rowValue = getRowValue(rsw, discriminatedResultMap, rowKey, null, partialObject); if (partialObject == null) { storeObject(resultHandler, resultContext, rowValue, parentMapping, resultSet); } } } if (rowValue != null && mappedStatement.isResultOrdered() && shouldProcessMoreRows(resultContext, rowBounds)) { storeObject(resultHandler, resultContext, rowValue, parentMapping, resultSet); previousRowValue = null; } else if (rowValue != null) { previousRowValue = rowValue; } }

我们找重点看吧:

// 看这行代码,获取行值 rowValue = getRowValue(rsw, discriminatedResultMap, rowKey, null, partialObject);

这其中 getRowValue 方法,我认为是比较重要的方法,处理逻辑大部分都在这里:

private Object getRowValue(ResultSetWrapper rsw, ResultMap resultMap, CacheKey combinedKey, String columnPrefix, Object partialObject) throws SQLException { // resultMap的唯一标志id 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())) { // 将行值包装成元数据对象MetaObject final MetaObject metaObject = configuration.newMetaObject(rowValue); boolean foundValues = this.useConstructorMappings; // 是否使用自动映射,因为我们自定义了resultMap,所以不会走这个 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; }

结果对象的创建,就在这里:

// 创建结果对象 rowValue = createResultObject(rsw, resultMap, lazyLoader, columnPrefix);

详细如下:

private Object createResultObject(ResultSetWrapper rsw, ResultMap resultMap, ResultLoaderMap lazyLoader, String columnPrefix) throws SQLException { this.useConstructorMappings = false; // reset previous mapping result final List


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有