博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Mybatis Mapper.xml 配置文件中 resultMap 节点的源码解析
阅读量:7095 次
发布时间:2019-06-28

本文共 11465 字,大约阅读时间需要 38 分钟。

hot3.png

相关文章

前言

在上篇文章  介绍了 Maper.xml 配置文件的解析,但是没有解析 resultMap 节点,因为该解析比较复杂,也比较难理解,所有单独拿出来进行解析。

在使用 Mybatis 的时候,都会使用resultMap节点来绑定列与bean属性的对应关系,但是一般就只会使用其简单的属性,他还有一些比较复杂的属性可以实现一些高级的功能,在没查看源码之前,我也只会简单的使用,很多高级的用法都没有使用过,通过这次学习,希望能在工作使用,能够写出简洁高效的SQL。

resultMap的定义

先来看看 resultMap 节点的官方定义:

简单的使用:

会把列名和属性名进行绑定,该节点一共有 4 个属性:

1. id :表示该 resultMap,共其他的语句调用

2. type:表示其对于的pojo类型,可以使用别名,也可以使用全限定类名

3. autoMapping:如果设置这个属性,MyBatis将会为这个ResultMap开启或者关闭自动映射。这个属性会覆盖全局的属性 autoMappingBehavior。默认值为:unset。

4. extends:继承,一个 resultMap 可以继承另一个 resultMap,这个属性是不是没有用过 ? ^^

接下来看下它可以有哪些子节点:

  • constructor - 用于注入结果到构造方法中
  • id – 标识ID列
  • result – 表示一般列
  • association – 关联查询
  • collection – 查询集合
  • discriminator - 鉴别器:mybatis可以使用discriminator判断某列的值,然后根据某列的值改变封装行为

constructor 

在查询数据库得到数据后,会把对应列的值赋值给javabean对象对应的属性,默认情况下mybatis会调用实体类的无参构造方法创建一个实体类,然后再给各个属性赋值,如果没有构造方法的时候,可以使用 constructor 节点进行绑定,如现有如下的构造方法:

public Person(int id, String name, String job, int age) {        this.id = id;        this.name = name;        this.job = job;        this.age = age;    }

 则,可以使用 constructor  节点进行绑定:

association 

关联查询,在级联中有一对一、一对多、多对多等关系,association主要是用来解决一对一关系的,association 可以有多种使用方式:

比如现在有一个 Person 类,它有一个 Address 属性,关联 Address 对象:

public class Person implements Serializable {    private int id;    private String name;    private String job;    private int age;    private Address address;}public class Address {    private int id;    private String name;    private long number;}

关联查询方式一:

关联查询方式二:

关联查询方式三:

collection 

collection 集合,如果pojo对象有一个属性是集合类型的,可以使用collection 来进行查询:

public class Person implements Serializable {    private int id;    private String name;    private String job;    private int age;    private List
addressList;}

当然还有其他的方法,具体可以参考官网。

discriminator

鉴别器,mybatis可以使用discriminator判断某列的值,然后根据某列的值改变封装行为,有点像 Java的 switch 语句,鉴别器指定了 column 和 javaType 属性。 列是 MyBatis 查找比较值的地方。 JavaType 是需要被用来保证等价测试的合适类型,

比如某列的值等于多少,则返回1,等于多少返回2等等。

以上就是 resultMap 节点的全部使用方法,下面是一个比较复杂的例子,源码解析会按照其来解析,例子来自于官方文档。

resultMap 源码解析

首先需要说明的是,一个 resultMap 节点会解析成一个 ResultMap 对象,而每个子节点(除了discriminator节点)会被解析成 ResultMapping 对象,即一个 ResultMap 包含的是 ResultMapping 对象的集合。

先来看看 ResultMapping 的一个声明:

public class ResultMapping {  // configuration 对象  private Configuration configuration;  private String property;  private String column;  private Class
javaType; private JdbcType jdbcType; private TypeHandler
typeHandler; // 对应的是 resultMap 属性,通过id来引用其他的resultMap private String nestedResultMapId; // 对应的是 select 属性,通过id来引用其他的select节点的定义 private String nestedQueryId; private Set
notNullColumns; private String columnPrefix; // 处理后的标志,标志有两个 id和constructor private List
flags; // 对应节点的column属性拆分后生成的结果,composites.size()>0会使column为null private List
composites; private String resultSet; private String foreignColumn; private boolean lazy;|

ResultMap 的声明如下:

public class ResultMap {  // ID,表示一个resultMap  private String id;  // 该resultMap对应的Javabean类型  private Class
type; // 对应的是除了discriminator节点外的其他节点 private List
resultMappings; // id 节点的映射集合 private List
idResultMappings; // 构造节点的集合 private List
constructorResultMappings; // 记录了映射关系中 不带有contructot节点的的映射关系 private List
propertyResultMappings; // column集合 private Set
mappedColumns; // discriminator 节点 private Discriminator discriminator; private boolean hasNestedResultMaps; private boolean hasNestedQueries; private Boolean autoMapping;}

解析:

resultMapElements(context.evalNodes("/mapper/resultMap"));  private void resultMapElements(List
list) throws Exception { for (XNode resultMapNode : list) { try { // 解析每个 resultMap 节点 resultMapElement(resultMapNode); } catch (IncompleteElementException e) { // ignore, it will be retried } } } private ResultMap resultMapElement(XNode resultMapNode) throws Exception { // 注意这里传入的是一个空的集合 return resultMapElement(resultMapNode, Collections.
emptyList()); }

主要的解析方法:

private ResultMap resultMapElement(XNode resultMapNode, List
additionalResultMappings) throws Exception { ErrorContext.instance().activity("processing " + resultMapNode.getValueBasedIdentifier()); // ID 属性 String id = resultMapNode.getStringAttribute("id", resultMapNode.getValueBasedIdentifier()); // type属性 String type = resultMapNode.getStringAttribute("type",resultMapNode.getStringAttribute("ofType", resultMapNode.getStringAttribute("resultType",resultMapNode.getStringAttribute("javaType")))); // extends 属性 String extend = resultMapNode.getStringAttribute("extends"); // autoMapping 属性 Boolean autoMapping = resultMapNode.getBooleanAttribute("autoMapping"); // 从注册的类型管理器里面查找对应的类型 Class
typeClass = resolveClass(type); // discriminator 节点 Discriminator discriminator = null; List
resultMappings = new ArrayList
(); resultMappings.addAll(additionalResultMappings); // 处理子节点 List
resultChildren = resultMapNode.getChildren(); for (XNode resultChild : resultChildren) { if ("constructor".equals(resultChild.getName())) { // 处理 constructor 节点 processConstructorElement(resultChild, typeClass, resultMappings); } else if ("discriminator".equals(resultChild.getName())) { // 处理discriminator节点 discriminator = processDiscriminatorElement(resultChild, typeClass, resultMappings); } else { List
flags = new ArrayList
(); if ("id".equals(resultChild.getName())) { flags.add(ResultFlag.ID); } // 处理其他节点,创建 resultMapping 对象并添加到集合中 resultMappings.add(buildResultMappingFromContext(resultChild, typeClass, flags)); } } ResultMapResolver resultMapResolver = new ResultMapResolver(builderAssistant, id, typeClass, extend, discriminator, resultMappings, autoMapping); try { // 创建代表该 resultMap 节点的 ResultMap 对象并添加到 ResultMap 集合中。 return resultMapResolver.resolve(); } catch (IncompleteElementException e) { // 解析失败,添加到集合,重新解析 configuration.addIncompleteResultMap(resultMapResolver); throw e; } }

处理 constructor 节点:

private void processConstructorElement(XNode resultChild, Class
resultType, List
resultMappings) throws Exception { List
argChildren = resultChild.getChildren(); for (XNode argChild : argChildren) { List
flags = new ArrayList
(); // 向集合中添加 contrucator 标志 flags.add(ResultFlag.CONSTRUCTOR); if ("idArg".equals(argChild.getName())) { // 添加id标志 flags.add(ResultFlag.ID); } // 创建 ResultMapping 对象并添加到集合中 resultMappings.add(buildResultMappingFromContext(argChild, resultType, flags)); } }

创建 ResultMapping 对象:

private ResultMapping buildResultMappingFromContext(XNode context, Class
resultType, List
flags) throws Exception { // 解析节点的属性 String property = context.getStringAttribute("property"); String column = context.getStringAttribute("column"); String javaType = context.getStringAttribute("javaType"); String jdbcType = context.getStringAttribute("jdbcType"); String nestedSelect = context.getStringAttribute("select"); String nestedResultMap = context.getStringAttribute("resultMap", processNestedResultMappings(context, Collections.
emptyList())); String notNullColumn = context.getStringAttribute("notNullColumn"); String columnPrefix = context.getStringAttribute("columnPrefix"); String typeHandler = context.getStringAttribute("typeHandler"); String resultSet = context.getStringAttribute("resultSet"); String foreignColumn = context.getStringAttribute("foreignColumn"); boolean lazy = "lazy".equals(context.getStringAttribute("fetchType", configuration.isLazyLoadingEnabled() ? "lazy" : "eager")); Class
javaTypeClass = resolveClass(javaType); @SuppressWarnings("unchecked") // 对应的 typeHandler 类型 Class
> typeHandlerClass = (Class
>) resolveClass(typeHandler); JdbcType jdbcTypeEnum = resolveJdbcType(jdbcType); // 创建 ResultMapping 对象 return builderAssistant.buildResultMapping(resultType, property, column, javaTypeClass, jdbcTypeEnum, nestedSelect, nestedResultMap, notNullColumn, columnPrefix, typeHandlerClass, flags, resultSet, foreignColumn, lazy); }

之后是创建 ResultMapped 对象并添加到集合中:

ResultMapResolver resultMapResolver = new ResultMapResolver(builderAssistant, id, typeClass, extend, discriminator, resultMappings, autoMapping);// 调用的使用 builderAssistant 的 addResultMap 方法return resultMapResolver.resolve();
public ResultMap addResultMap(String id, Class
type, String extend, Discriminator discriminator, List
resultMappings, Boolean autoMapping) { // 为 id 加上 namespace即 namespace.id id = applyCurrentNamespace(id, false); extend = applyCurrentNamespace(extend, true); if (extend != null) { if (!configuration.hasResultMap(extend)) { throw new IncompleteElementException("Could not find a parent resultmap with id '" + extend + "'"); } // 获取父级的resultMap ResultMap resultMap = configuration.getResultMap(extend); List
extendedResultMappings = new ArrayList
(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
extendedResultMappingsIter = extendedResultMappings.iterator(); while (extendedResultMappingsIter.hasNext()) { if (extendedResultMappingsIter.next().getFlags().contains(ResultFlag.CONSTRUCTOR)) { extendedResultMappingsIter.remove(); } } } resultMappings.addAll(extendedResultMappings); } // 创建 resultMap ResultMap resultMap = new ResultMap.Builder(configuration, id, type, resultMappings, autoMapping) .discriminator(discriminator) .build(); // 添加到集合 configuration.addResultMap(resultMap); return resultMap; }

到这里,就把 resultMap 节点解析完毕了,之后在解析 Mapper.xml 文件的其他节点,参考 

转载于:https://my.oschina.net/mengyuankan/blog/2877810

你可能感兴趣的文章
梦断代码读后感
查看>>
jdbc的配置及jdbc连接常用数据库(mysql、sqlserver、Oracle)
查看>>
java获取程序执行时间
查看>>
eclipse连hadoop2.x运行wordcount 转载
查看>>
HTML5:Details元素
查看>>
WEB前端底层知识之浏览器是如何工作的(2)--渲染引擎 BY: linFen
查看>>
ActionBar的简单应用
查看>>
IE11下不能引入外部css的解决方法
查看>>
java web 答辩总结
查看>>
GUI测试含义
查看>>
javabean使用技巧
查看>>
JS/JQ综合总结
查看>>
CGAffineTransform相关函数
查看>>
字符编码与字符集区别与联系(网页/PHP文件/MYSQL数据库乱码问题)
查看>>
黑马程序员-----const和readonly的区别
查看>>
转载:基于MapXtreme的鹰眼功能
查看>>
黄聪:远程序桌面登录的.NET(C#)开发
查看>>
JMeter聚合报告(Aggregate Report)理解
查看>>
C# 多线程Thread.IsBackground=True的作用
查看>>
Oracle数据库安装问题记录
查看>>