文档章节

MyBatis整合Spring的实现(11)

tara_qri
 tara_qri
发布于 2015/10/26 22:18
字数 1602
阅读 183
收藏 4

前一章节已经介绍了,把方法分解成什么样子来分析,这里先来分析一个方法resultMapElements,在这个方法前还有cacheRefElement与cacheElement,但是由于配置文件中没有配置这2项,所以这里就先跳过。而parameterMapElement在最新的MyBatis中是过时的,也先跳过,以后可以在补充。

1 配置文件

<resultMap id="BaseResultMap" type="cn.vansky.schedule.time.menu.bo.Menu">
    <!--
      WARNING - @mbggenerated
      This element is automatically generated by MyBatis Generator, do not modify.
      This element was generated on Fri Aug 14 16:08:36 CST 2015.
    -->
    <id column="Id" property="id" jdbcType="INTEGER" />
    <result column="menu_name" property="menuName" jdbcType="VARCHAR" />
    <result column="menu_remark" property="menuRemark" jdbcType="VARCHAR" />
    <result column="menu_parent_id" property="menuParentId" jdbcType="INTEGER" />
    <result column="menu_url" property="menuUrl" jdbcType="VARCHAR" />
    <result column="is_show" property="isShow" jdbcType="TINYINT" />
    <result column="is_delete" property="isDelete" jdbcType="TINYINT" />
    <result column="operation_user_name" property="operationUserName" jdbcType="VARCHAR" />
    <result column="operation_time" property="operationTime" jdbcType="TIMESTAMP" />
  </resultMap>

这里是使用自己扩展MyBatis的自动生成代码,生成的resultMap配置。

2 代码

private void resultMapElements(List<XNode> list) throws Exception {
    for (XNode resultMapNode : list) {
      try {
        resultMapElement(resultMapNode);
      } catch (IncompleteElementException e) {
        // ignore, it will be retried
      }
    }
  }
  private ResultMap resultMapElement(XNode resultMapNode) throws Exception {
    return resultMapElement(resultMapNode, Collections.<ResultMapping> emptyList());
}

这里是获取当前文件中所有resultMap对应的XML,然后分别对每个resultMap进行处理这里会去捕获一个专门的异常,目前还不清楚是起什么作用,先继续往下分析。
3 方法resultMapElement

// resultMapNode是对应的resuleMap的XML信息,这里首先获取配置中的id,如果没有就自动生成一个id
// BaseResultMap
String id = resultMapNode.getStringAttribute("id", resultMapNode.getValueBasedIdentifier());
// 那么这行很明显是获取type了,如果没有就获取ofType,还没有就获取resultType,还是没有就获取javaType
// cn.vansky.schedule.time.menu.bo.Menu
String type = resultMapNode.getStringAttribute("type", 
resultMapNode.getStringAttribute("ofType",
resultMapNode.getStringAttribute("resultType", resultMapNode.getStringAttribute("javaType"))));
// 猜想是获取继承的父类
// null
String extend = resultMapNode.getStringAttribute("extends");
// null
Boolean autoMapping = resultMapNode.getBooleanAttribute("autoMapping");
// 获取type对应的Class
Class<?> typeClass = resolveClass(type);
Discriminator discriminator = null;
List<ResultMapping> resultMappings = new ArrayList<ResultMapping>();
// 这里additionalResultMappings是空列表,而不是null
resultMappings.addAll(additionalResultMappings);
// 获取子节点id及result
List<XNode> resultChildren = resultMapNode.getChildren();
for (XNode resultChild : resultChildren) {
    if ("constructor".equals(resultChild.getName())) {
        processConstructorElement(resultChild, typeClass, resultMappings);
    } else if ("discriminator".equals(resultChild.getName())) {
        discriminator = processDiscriminatorElement(resultChild, typeClass, resultMappings);
    } else {
        // id与result都走这里
        ArrayList<ResultFlag> flags = new ArrayList<ResultFlag>();
        if ("id".equals(resultChild.getName())) {
          flags.add(ResultFlag.ID);
        }
        resultMappings.add(buildResultMappingFromContext(resultChild, typeClass, flags));
    }
}

4 buildResultMappingFromContext

以下都是以ID为例,进行分析。

private ResultMapping buildResultMappingFromContext(XNode context, Class<?> resultType, ArrayList<ResultFlag> flags) throws Exception {
    // id
    String property = context.getStringAttribute("property");
    // Id
    String column = context.getStringAttribute("column");
    // null
    String javaType = context.getStringAttribute("javaType");
    // INTEGER
    String jdbcType = context.getStringAttribute("jdbcType");
    // null
    String nestedSelect = context.getStringAttribute("select");
    // null 
    String nestedResultMap = context.getStringAttribute("resultMap",
        processNestedResultMappings(context, Collections.<ResultMapping> emptyList()));
    // null
    String notNullColumn = context.getStringAttribute("notNullColumn");
    // null
    String columnPrefix = context.getStringAttribute("columnPrefix");
    // null
    String typeHandler = context.getStringAttribute("typeHandler");
    // null
    String resulSet = context.getStringAttribute("resultSet");
    // null
    String foreignColumn = context.getStringAttribute("foreignColumn");
    // false
    boolean lazy = "lazy".equals(context.getStringAttribute("fetchType", configuration.isLazyLoadingEnabled() ? "lazy" : "eager"));
    // null
    Class<?> javaTypeClass = resolveClass(javaType);
    @SuppressWarnings("unchecked")
    // null
    Class<? extends TypeHandler<?>> typeHandlerClass = (Class<? extends TypeHandler<?>>) resolveClass(typeHandler);
    // 获取到JdbcType
    JdbcType jdbcTypeEnum = resolveJdbcType(jdbcType);
    // 这里就会构建生成一个ResultMapping
    return builderAssistant.buildResultMapping(resultType, property, column, javaTypeClass, jdbcTypeEnum, nestedSelect, nestedResultMap, notNullColumn, columnPrefix, typeHandlerClass, flags, resulSet, foreignColumn, lazy);
}

5 MapperBuilderAssistant的buildResultMapping方法

public ResultMapping buildResultMapping(
      Class<?> resultType,
      String property,
      String column,
      Class<?> javaType,
      JdbcType jdbcType,
      String nestedSelect,
      String nestedResultMap,
      String notNullColumn,
      String columnPrefix,
      Class<? extends TypeHandler<?>> typeHandler,
      List<ResultFlag> flags,
      String resultSet,
      String foreignColumn, 
      boolean lazy) {
    // 这里如果配置中有javaType属性直接返回,否则通过type配置的类及属性获取对应的Class
    Class<?> javaTypeClass = resolveResultJavaType(resultType, property, javaType);
    // 获取类型处理器 null
    TypeHandler<?> typeHandlerInstance = resolveTypeHandler(javaTypeClass, typeHandler);
    // 0
    List<ResultMapping> composites = parseCompositeColumnName(column);
    if (composites.size() > 0) column = null;
    // 初始化一些内部信息
    ResultMapping.Builder builder = new ResultMapping.Builder(configuration, property, column, javaTypeClass);
    builder.jdbcType(jdbcType);
    builder.nestedQueryId(applyCurrentNamespace(nestedSelect, true));
    builder.nestedResultMapId(applyCurrentNamespace(nestedResultMap, true));
    builder.resultSet(resultSet);
    builder.typeHandler(typeHandlerInstance);
    builder.flags(flags == null ? new ArrayList<ResultFlag>() : flags);
    builder.composites(composites);
    builder.notNullColumns(parseMultipleColumnNames(notNullColumn));
    builder.columnPrefix(columnPrefix);
    builder.foreignColumn(foreignColumn);
    builder.lazy(lazy);
    return builder.build();
  }

以上生成的ResultMapping的typeHandler还是为null的,因为这里获取的是在配置文件中对应的TypeHandler。那么就看一下builder.build()里面是什么代码。

public ResultMapping build() {
      // lock down collections
      resultMapping.flags = Collections.unmodifiableList(resultMapping.flags);
      resultMapping.composites = Collections.unmodifiableList(resultMapping.composites);
      resolveTypeHandler();
      validate();
      return resultMapping;
}

原来这里根据配置信息解析出默认使用的TypeHandler,还对一些ResultMapping的信息做了验证,具体代码,自行研究就可以了。

6 ResultMapping

6.1 属性

ID最后对应的ResultMapping的信息。

/** 全局配置类 */
private Configuration configuration;
/** id */
private String property;
/** Id */
private String column;
/** java.lang.Integer */
private Class<?> javaType;
/** INTEGER */
private JdbcType jdbcType;
/** IntegerTypeHandler  */
private TypeHandler<?> typeHandler;
/** null */
private String nestedResultMapId;
/** null */
private String nestedQueryId;
/** 空列表 */
private Set<String> notNullColumns;
/** null */
private String columnPrefix;
/** ID */
private List<ResultFlag> flags;
/** 空列表 */
private List<ResultMapping> composites;
/** null */
private String resultSet;
/** null */
private String foreignColumn;
/** false */
private boolean lazy;

menu_name最后对应的ResultMapping的信息。

/** 全局配置类 */
private Configuration configuration;
/** menuName */
private String property;
/** menu_name */
private String column;
/** java.lang.String */
private Class<?> javaType;
/** VARCHAR */
private JdbcType jdbcType;
/** StringTypeHandler */
private TypeHandler<?> typeHandler;
/** null */
private String nestedResultMapId;
/** null */
private String nestedQueryId;
/** 空列表 */
private Set<String> notNullColumns;
/** null */
private String columnPrefix;
/** 空列表 */
private List<ResultFlag> flags;
/** 空列表 */
private List<ResultMapping> composites;
/** null */
private String resultSet;
/** null */
private String foreignColumn;
/** false */
private boolean lazy;

MyBatis的地址http://mybatis.github.io/mybatis-3/zh/sqlmap-xml.html#Result_Maps这里有很多例子,喜欢的童鞋可以多去研究一下。

当对id及result都遍历以后,会生成List<ResultMapping>。

ResultMapResolver resultMapResolver = new ResultMapResolver(builderAssistant, id, typeClass, extend, discriminator, resultMappings, autoMapping);
    try {
      return resultMapResolver.resolve();
    } catch (IncompleteElementException  e) {
      configuration.addIncompleteResultMap(resultMapResolver);
      throw e;
    }

如果这里解析失败会抛出前面出现的捕获异常,并把错误的解析放入Configuration(全局配置类)的Collection<ResultMapResolver> incompleteResultMaps = new LinkedList<ResultMapResolver>()。

MapperBuilderAssistant的addResultMap方法

public ResultMap addResultMap(
      String id,
      Class<?> type,
      String extend,
      Discriminator discriminator,
      List<ResultMapping> resultMappings,
      Boolean autoMapping) {
    // 这里把命名空间与id合并
    // cn.vansky.schedule.time.menu.dao.MenuMapper.BaseResultMap
    id = applyCurrentNamespace(id, false);
    // null 
    extend = applyCurrentNamespace(extend, true);
    ResultMap.Builder resultMapBuilder = new ResultMap.Builder(configuration, id, type, resultMappings, autoMapping);
    if (extend != null) {
      if (!configuration.hasResultMap(extend)) {
        throw new IncompleteElementException("Could not find a parent resultmap with id '" + extend + "'");
      }
      ResultMap resultMap = configuration.getResultMap(extend);
      List<ResultMapping> extendedResultMappings = new ArrayList<ResultMapping>(resultMap.getResultMappings());
      extendedResultMappings.removeAll(resultMappings);
      // Remove parent constructor if this resultMap declares a constructor.
      boolean declaresConstructor = false;
      for (ResultMapping resultMapping : resultMappings) {
        if (resultMapping.getFlags().contains(ResultFlag.CONSTRUCTOR)) {
          declaresConstructor = true;
          break;
        }
      }
      if (declaresConstructor) {
        Iterator<ResultMapping> extendedResultMappingsIter = extendedResultMappings.iterator();
        while (extendedResultMappingsIter.hasNext()) {
          if (extendedResultMappingsIter.next().getFlags().contains(ResultFlag.CONSTRUCTOR)) {
            extendedResultMappingsIter.remove();
          }
        }
      }
      resultMappings.addAll(extendedResultMappings);
    }
    resultMapBuilder.discriminator(discriminator);
    // 这里把新增的ResultMapping做了处理
    ResultMap resultMap = resultMapBuilder.build();
    configuration.addResultMap(resultMap);
    return resultMap;
  }

这里没有具体介绍,还需要慢慢深究。下面来看最终的ResultMap信息。

8 ResultMap属性

// cn.vansky.schedule.time.menu.dao.MenuMapper.BaseResultMap
private String id;
// cn.vansky.schedule.time.menu.bo.Menu
private Class<?> type;
// 对应配置中的所有结果列,这里9个对象
private List<ResultMapping> resultMappings;
// 对应配置中的id列,这里1个对象
private List<ResultMapping> idResultMappings;
// 对应构造器的列,这里为0个对象
private List<ResultMapping> constructorResultMappings;
// 看代码得出,只要不是构造器列,就属于这里,也就是包括id和result
private List<ResultMapping> propertyResultMappings;
// 对应的配置的列名全部大写,这里使用的set所以也就不是按顺序来排列的了
// MENU_PARENT_ID,MENU_NAME,MENU_URL,OPERATION_TIME,IS_SHOW,OPERATION_USER_NAME,ID,IS_DELETE,MENU_REMARK
private Set<String> mappedColumns;
// null
private Discriminator discriminator;
// false
private boolean hasNestedResultMaps;
// false
private boolean hasNestedQueries;
// null
private Boolean autoMapping;

至此最终的ResultMap信息出来了。

总结:

这里很多东西,作者也是一点一点去研究,而且实际项目中的配置也不是特别的多,所以有些还待完善。


© 著作权归作者所有

tara_qri
粉丝 10
博文 48
码字总数 21496
作品 1
海淀
私信 提问
ZHENFENGSHISAN/perfect-ssm

Quick Start 项目简介 ssm系列 ssm-demo:Spring+SpringMVC+Mybatis+easyUI整合 perfect-ssm:RESTful API+redis缓存 ssm-cluster:前后端分离+集群部署 ssm-dubbo:dubbo服务化 ssm-micro-se......

ZHENFENGSHISAN
2017/09/18
0
0
springmvc 项目完整示例01 需求与数据库表设计 简单的springmvc应用实例 web项目

一个简单的用户登录系统 用户有账号密码,登录ip,登录时间 打开登录页面,输入用户名密码 登录日志,可以记录登陆的时间,登陆的ip 成功登陆了的话,就更新用户的最后登入时间和ip,同时记录一条登...

noteless
2016/02/24
0
0
shenzhanwang/SSM

SSM SpringMVC,Mybatis,Spring三大框架的整合总是很麻烦,在此提供一个已经整合好三大框架的包,可以直接下载导入Myeclipse使用,项目基于Maven做依赖管理。项目基于Mysql自带的Sakila数据库...

shenzhanwang
2016/11/16
0
0
Spring Boot 整合 MyBatis

最近项目原因可能会继续开始使用MyBatis,已经习惯于spring-data的风格,再回头看xml的映射配置总觉得不是特别舒服,接口定义与映射离散在不同文件中,使得阅读起来并不是特别方便。 Spring...

中关村的老男孩
06/24
68
0
Spring与MyBatis整合

序言 在MyBatis学习中,我们会发现很多重复性的代码,例如: //创建连接 private SqlSessionFactory sqlSessionFactory = SessionFactoryUtils .getSessionfactory().getSqlSessionFactory(......

开源俱乐部
2014/07/09
446
0

没有更多内容

加载失败,请刷新页面

加载更多

OSChina 周六乱弹 —— 早上儿子问我他是怎么来的

Osc乱弹歌单(2019)请戳(这里) 【今日歌曲】 @凉小生 :#今日歌曲推荐# 少点戾气,愿你和这个世界温柔以待。中岛美嘉的单曲《僕が死のうと思ったのは (曾经我也想过一了百了)》 《僕が死の...

小小编辑
今天
2.4K
15
Excption与Error包结构,OOM 你遇到过哪些情况,SOF 你遇到过哪些情况

Throwable 是 Java 中所有错误与异常的超类,Throwable 包含两个子类,Error 与 Exception 。用于指示发生了异常情况。 Java 抛出的 Throwable 可以分成三种类型。 被检查异常(checked Exc...

Garphy
今天
41
0
计算机实现原理专题--二进制减法器(二)

在计算机实现原理专题--二进制减法器(一)中说明了基本原理,现准备说明如何来实现。 首先第一步255-b运算相当于对b进行按位取反,因此可将8个非门组成如下图的形式: 由于每次做减法时,我...

FAT_mt
昨天
40
0
好程序员大数据学习路线分享函数+map映射+元祖

好程序员大数据学习路线分享函数+map映射+元祖,大数据各个平台上的语言实现 hadoop 由java实现,2003年至今,三大块:数据处理,数据存储,数据计算 存储: hbase --> 数据成表 处理: hive --> 数...

好程序员官方
昨天
61
0
tabel 中含有复选框的列 数据理解

1、el-ui中实现某一列为复选框 实现多选非常简单: 手动添加一个el-table-column,设type属性为selction即可; 2、@selection-change事件:选项发生勾选状态变化时触发该事件 <el-table @sel...

everthing
昨天
21
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部