Mybatis源码分析之(五)mapper如何将数据库数据转换成java对象的

x33g5p2x  于2022-01-11 转载在 Java  
字(9.7k)|赞(0)|评价(0)|浏览(470)

本篇对mybatis从取到数据库数据开始到映射成对象并返回的过程进行了详细的分析。

转换ResultSet成java对象

下面的代码是PreparedStatementHandler中的

  1. @Override
  2. public <E> Cursor<E> queryCursor(Statement statement) throws SQLException {
  3. PreparedStatement ps = (PreparedStatement) statement;
  4. //这里是执行sql并得到ResultSet
  5. ps.execute();
  6. //这里是真正处理ResultSet,将之转换成java对象的地方
  7. return resultSetHandler.<E> handleCursorResultSets(ps);
  8. }

//resultSetHandler是DefaultResultSetHandler类型的

  1. @Override
  2. public List<Object> handleResultSets(Statement stmt) throws SQLException {
  3. ErrorContext.instance().activity("handling results").object(mappedStatement.getId());
  4. final List<Object> multipleResults = new ArrayList<Object>();
  5. int resultSetCount = 0;
  6. //把statement中的ResultSet用ResultSetWrapper包装起来(里面有处理类对象的,列名,类名,列名映射等字段)
  7. ResultSetWrapper rsw = getFirstResultSet(stmt);
  8. //获得mappedStatement中的ResultMaps(这个在初始化configuration的时候就已经生成好了,这里只是取出来)
  9. List<ResultMap> resultMaps = mappedStatement.getResultMaps();
  10. int resultMapCount = resultMaps.size();
  11. //如果rsw不为空,但是resultMapCount小于1就报错(很容易理解,就是有返回结果,但是没有映射,所以mybatis不知道怎么把结果转换成java类,当然就报错了)
  12. validateResultMapsCount(rsw, resultMapCount);
  13. while (rsw != null && resultMapCount > resultSetCount) {
  14. //拿到resultMap
  15. ResultMap resultMap = resultMaps.get(resultSetCount);
  16. //处理ResultSet,将处理好的结果存到multipleResults(具体看下面的函数)
  17. handleResultSet(rsw, resultMap, multipleResults, null);
  18. //从上面这个函数出来的时候,multipleResults已经是存有结果的list了
  19. //若stmt还有下一个ResultSet,则继续循环
  20. rsw = getNextResultSet(stmt);
  21. cleanUpAfterHandlingResultSet();
  22. resultSetCount++;
  23. }
  24. //若你的mapper配置文件中配了这个ResultSets属性的话就取出来往下面走(不过一般都不会用到,最少LZ到现在还没有用过)
  25. String[] resultSets = mappedStatement.getResultSets();
  26. if (resultSets != null) {
  27. //不常用就不细细分析了,看完这整篇后,你对mybatis已经有了比较清晰的逻辑了
  28. while (rsw != null && resultSetCount < resultSets.length) {
  29. ResultMapping parentMapping = nextResultMaps.get(resultSets[resultSetCount]);
  30. if (parentMapping != null) {
  31. String nestedResultMapId = parentMapping.getNestedResultMapId();
  32. ResultMap resultMap = configuration.getResultMap(nestedResultMapId);
  33. handleResultSet(rsw, resultMap, null, parentMapping);
  34. }
  35. rsw = getNextResultSet(stmt);
  36. cleanUpAfterHandlingResultSet();
  37. resultSetCount++;
  38. }
  39. }
  40. //最后返回结果集
  41. return collapseSingleResultList(multipleResults);
  42. }
  43. //处理过程
  44. private void handleResultSet(ResultSetWrapper rsw, ResultMap resultMap, List<Object> multipleResults, ResultMapping parentMapping) throws SQLException {
  45. try {
  46. //如果有parentMapping则走下面
  47. if (parentMapping != null) {
  48. //进行处理
  49. handleRowValues(rsw, resultMap, null, RowBounds.DEFAULT, parentMapping);
  50. } else {
  51. //若resultHandler为空则走下面
  52. if (resultHandler == null) {
  53. //初始化一个DefaultResultHandler
  54. DefaultResultHandler defaultResultHandler = new DefaultResultHandler(objectFactory);
  55. //进行处理
  56. handleRowValues(rsw, resultMap, defaultResultHandler, rowBounds, null);
  57. //multipleResults中加defaultResultHandler里面的结果集
  58. multipleResults.add(defaultResultHandler.getResultList());
  59. } else {
  60. //进行处理
  61. handleRowValues(rsw, resultMap, resultHandler, rowBounds, null);
  62. }
  63. }
  64. } finally {
  65. // issue #228 (close resultsets)
  66. //最后关闭ResultSet回到handleResultSets
  67. closeResultSet(rsw.getResultSet());
  68. }
  69. }
  70. //其实最后走的都是这个函数
  71. public void handleRowValues(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping) throws SQLException {
  72. //看是否有嵌套的ResultMap,(比如使用了association, collection标签)
  73. if (resultMap.hasNestedResultMaps()) {
  74. ensureNoRowBounds();
  75. checkResultHandler();
  76. //处理嵌套ResultMap
  77. handleRowValuesForNestedResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);
  78. } else {
  79. //处理简单的ResultMap(以这个为例子)
  80. handleRowValuesForSimpleResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);
  81. }
  82. }
  83. //处理简单的ResultMap
  84. private void handleRowValuesForSimpleResultMap(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping)
  85. throws SQLException {
  86. DefaultResultContext<Object> resultContext = new DefaultResultContext<Object>();
  87. //若有分页,则先跳过前面的行数(因为mybatis自带的分页是内存分页,全部数据都取到服务器在进行分页的)
  88. skipRows(rsw.getResultSet(), rowBounds);
  89. while (shouldProcessMoreRows(resultContext, rowBounds) && rsw.getResultSet().next()) {//若要继续处理列并且resultSet还有列则处理
  90. //这步拿到要进行处理的resultmap
  91. ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(rsw.getResultSet(), resultMap, null);
  92. //获得整行的数据,根据map映射成java对象
  93. Object rowValue = getRowValue(rsw, discriminatedResultMap);
  94. //把结果存好,存在resultHandler中的list中(DefaultResultHandler中有一个字段 List<Object> list用来存储这个结果)
  95. storeObject(resultHandler, resultContext, rowValue, parentMapping, rsw.getResultSet());
  96. }
  97. }

新建对象并赋值

  1. private Object getRowValue(ResultSetWrapper rsw, ResultMap resultMap) throws SQLException {
  2. final ResultLoaderMap lazyLoader = new ResultLoaderMap();
  3. //创建一个对象来接受数据(根据配置生成相应的对象)
  4. Object rowValue = createResultObject(rsw, resultMap, lazyLoader, null);
  5. if (rowValue != null && !hasTypeHandlerForResultObject(rsw, resultMap.getType())) {
  6. final MetaObject metaObject = configuration.newMetaObject(rowValue);
  7. boolean foundValues = this.useConstructorMappings;
  8. //看是否需要自动映射
  9. if (shouldApplyAutomaticMappings(resultMap, false)) {
  10. //自动映射,把结果放到metaObject的originalObject也就是rowValue中(具体函数看下方)
  11. foundValues = applyAutomaticMappings(rsw, resultMap, metaObject, null) || foundValues;
  12. }
  13. //通过属性映射来找
  14. foundValues = applyPropertyMappings(rsw, resultMap, metaObject, lazyLoader, null) || foundValues;
  15. foundValues = lazyLoader.size() > 0 || foundValues;
  16. //看这段貌似可以在configuration中设置若找不到就实例化一个初始的对象
  17. rowValue = (foundValues || configuration.isReturnInstanceForEmptyRow()) ? rowValue : null;
  18. }
  19. //返回解析好的行值
  20. return rowValue;
  21. }

通过mapping映射属性

  1. private boolean applyAutomaticMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject, String columnPrefix) throws SQLException {
  2. //这个是自动获取mapping,也是比较重要的函数(下方有具体的分析)
  3. List<UnMappedColumnAutoMapping> autoMapping = createAutomaticMappings(rsw, resultMap, metaObject, columnPrefix);
  4. boolean foundValues = false;
  5. if (autoMapping.size() > 0) {
  6. for (UnMappedColumnAutoMapping mapping : autoMapping) {
  7. //遍历autoMapping
  8. //从resultSet中解析出值
  9. //解析的方法很简单,就不跟了,大概就是调用typeHandler中的get函数,取出和列名相对应的值就行了
  10. final Object value = mapping.typeHandler.getResult(rsw.getResultSet(), mapping.column);
  11. if (value != null) {
  12. //value不为空说明找到了
  13. foundValues = true;
  14. }
  15. if (value != null || (configuration.isCallSettersOnNulls() && !mapping.primitive)) {
  16. // gcode issue #377, call setter on nulls (value is not 'found')
  17. //找到了就把值设置到 metaObject中的objectWrapper中的object中。其实就是metaObject中的originalObject
  18. metaObject.setValue(mapping.property, value);
  19. }
  20. }
  21. }
  22. //返回是否找到
  23. return foundValues;
  24. }

获取Mapping

  1. //创建自动映射的mapping
  2. private List<UnMappedColumnAutoMapping> createAutomaticMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject, String columnPrefix) throws SQLException {
  3. final String mapKey = resultMap.getId() + ":" + columnPrefix;
  4. 看缓存里有没有
  5. List<UnMappedColumnAutoMapping> autoMapping = autoMappingsCache.get(mapKey);
  6. //没有就自己造
  7. if (autoMapping == null) {
  8. //存放映射的UnMappedColumnAutoMapping(一个对应一个字段映射)
  9. autoMapping = new ArrayList<UnMappedColumnAutoMapping>();
  10. //通过resultSetWrapper来创建未映射的字段的映射(具体方法看下面)
  11. final List<String> unmappedColumnNames = rsw.getUnmappedColumnNames(resultMap, columnPrefix);
  12. for (String columnName : unmappedColumnNames) {
  13. //轮询unmappedColumnNames
  14. String propertyName = columnName;
  15. if (columnPrefix != null && !columnPrefix.isEmpty()) {
  16. // When columnPrefix is specified,
  17. // ignore columns without the prefix.
  18. if (columnName.toUpperCase(Locale.ENGLISH).startsWith(columnPrefix)) {
  19. propertyName = columnName.substring(columnPrefix.length());
  20. } else {
  21. continue;
  22. }
  23. }
  24. //通过metaObject找到属性
  25. final String property = metaObject.findProperty(propertyName, configuration.isMapUnderscoreToCamelCase());
  26. //如果属性不为空且有Set方法的话进入方法
  27. if (property != null && metaObject.hasSetter(property)) {
  28. //查看该字段set的是什么类型
  29. final Class<?> propertyType = metaObject.getSetterType(property);
  30. //看typeHandlerRegistry有没有处理这种类型的handle,有的话继续
  31. if (typeHandlerRegistry.hasTypeHandler(propertyType, rsw.getJdbcType(columnName))) {
  32. //获取TypeHandler
  33. final TypeHandler<?> typeHandler = rsw.getTypeHandler(propertyType, columnName);
  34. //生成UnMappedColumnAutoMapping放到autoMapping里
  35. autoMapping.add(new UnMappedColumnAutoMapping(columnName, property, typeHandler, propertyType.isPrimitive()));
  36. } else {
  37. configuration.getAutoMappingUnknownColumnBehavior()
  38. .doAction(mappedStatement, columnName, property, propertyType);
  39. }
  40. } else{
  41. configuration.getAutoMappingUnknownColumnBehavior()
  42. .doAction(mappedStatement, columnName, (property != null) ? property : propertyName, null);
  43. }
  44. }
  45. 放到cache
  46. autoMappingsCache.put(mapKey, autoMapping);
  47. }
  48. //返回autoMapping(回到applyAutomaticMappings方法)
  49. return autoMapping;
  50. }

//ResultSetWrapper类中

  1. public List<String> getUnmappedColumnNames(ResultMap resultMap, String columnPrefix) throws SQLException {
  2. //看缓存有没有,没有自己造,有就直接返回
  3. List<String> unMappedColumnNames = unMappedColumnNamesMap.get(getMapKey(resultMap, columnPrefix));
  4. if (unMappedColumnNames == null) {
  5. //加载映射和没映射字段
  6. loadMappedAndUnmappedColumnNames(resultMap, columnPrefix);
  7. unMappedColumnNames = unMappedColumnNamesMap.get(getMapKey(resultMap, columnPrefix));
  8. }
  9. return unMappedColumnNames;
  10. }
  11. private void loadMappedAndUnmappedColumnNames(ResultMap resultMap, String columnPrefix) throws SQLException {
  12. List<String> mappedColumnNames = new ArrayList<String>();
  13. List<String> unmappedColumnNames = new ArrayList<String>();
  14. final String upperColumnPrefix = columnPrefix == null ? null : columnPrefix.toUpperCase(Locale.ENGLISH);
  15. //获取已经映射过的column
  16. final Set<String> mappedColumns = prependPrefixes(resultMap.getMappedColumns(), upperColumnPrefix);
  17. //轮询里面ResultSetWrapper中的columnNames
  18. for (String columnName : columnNames) {
  19. //转成大写比对
  20. final String upperColumnName = columnName.toUpperCase(Locale.ENGLISH);
  21. //若mappedColumns中有此column
  22. if (mappedColumns.contains(upperColumnName)) {
  23. //加入到mappedColumnNames
  24. mappedColumnNames.add(upperColumnName);
  25. } else {
  26. //否则放入unmappedColumnNames
  27. unmappedColumnNames.add(columnName);
  28. }
  29. }
  30. //最后将mappedColumnNames放到mappedColumnNamesMap
  31. mappedColumnNamesMap.put(getMapKey(resultMap, columnPrefix), mappedColumnNames);
  32. //最后将unmappedColumnNames放到unMappedColumnNamesMap
  33. unMappedColumnNamesMap.put(getMapKey(resultMap, columnPrefix), unmappedColumnNames);
  34. }

总结

其实就几个重要的点。
1.创建对象
2.获得resultHandle
3.获得mapping
4.获得typeHandle
5.通过handle和mapping给对象赋值,然后把对象存到resultHandle中
6.最后返回

相关文章

最新文章

更多