MyBatis源码分析_结果集映射规则详细分析(8)

目录

1. 简介

2.  无嵌套映射关系

2.1 handleRowValuesForSimpleResultMap 方法对行进行映射处理

2.2 getRowValue方法针对读取ResultSet对象进行映射 

2.2.1 没有配置ResultMap的进行自动映射

2.2.2 配置ResultMap的映射

3. 有嵌套的映射关系

3.1  嵌套的行数据 getRowValue方法

3.1.1 针对TUser表的映射

 3.1.2 再次处理相同的TUser


1. 简介

本篇是对上一篇的补充,建议先看上一篇了解整个映射流程,然后再看本篇了解详细的映射规则。

在上一篇MyBatis源码分析_ResultSetHandler(7)_chen_yao_kerr的博客-CSDN博客的第4段落,我们已经介绍了无嵌套结果集的映射规则。其实,映射分为2种,有嵌套结果集的和无嵌套结果集的。

2.  无嵌套映射关系

什么叫无嵌套映射关系呢?简单点说就是单表查询的结果,不涉及内、外连接。比如:

我们以TUser表单表查询为例,这就属于无嵌套的查询。而mybatis针对这些无嵌套映射的结果查询,就是用简单的映射规则,如下:

 而它走的就是无嵌套的特有方法逻辑,如下:

 下面的逻辑,则和上一篇MyBatis源码分析_ResultSetHandler(7)_chen_yao_kerr的博客-CSDN博客的第四段落相同,都是关于无嵌套映射的处理逻辑。

2.1 handleRowValuesForSimpleResultMap 方法对行进行映射处理

而这个方法的核心逻辑就是getRowValue方法,它是获取行数据的。

2.2 getRowValue方法针对读取ResultSet对象进行映射 

 其实,它就干了以上的4个核心步骤的活,就完成了一个最简单的Pojo对象的映射工作。下面针对3和4两个步骤,详细的看一下没有配置ResultMap和配置了ResultMap的逻辑有何不同之处。

2.2.1 没有配置ResultMap的进行自动映射

所谓的没有配置ResultMap的SQL,mybatis会进行自动填充,填充的column和property值是一样的。这就是我们所谓的自动映射 (字段名 和 Pojo的属性名  必须一致

自动填充完映射规则以后,我们需要根据自行填充的映射规则进行映射。其实,逻辑就是根据column去ResultSet中获取值,然后把值按照property属性设置到POJO中。而POJO则是封装在MetaObject对象中

2.2.2 配置ResultMap的映射

如果已经有了ResultMap的映射规则,那么我们是不会进行自动填充映射规则的。也就是说上面的自动映射逻辑不会走的。

我们会根据在xml中配置的ResultMap信息,直接获取到xml配置好的映射规则。具体逻辑就是先获取到column,然后根据column获取到封装 映射规则的 ResultMapping 对象。

而正确的设置值的地方在下面的  applyPropertyMappings 方法中

这边稍微提一下TypeHandler对象,它就是根据不同类型,用不同的方式从ResultSet中获取值的。而TypeHandler的类型有很多,比如IntergerTypeHandler:

按照模板设计原则,我们只需要调用父类的公用方法,然后就会调到具体的子类的实现方法中去,如下:

由于ID是Integer类型的,因此它实际调用的是IntegerTypeHandler的getResult方法。而最终,必然调用resultSet的getInt方法

而如果是一个String类型的字段,比如userName。它则会调用到StringTypeHandler类中的此方法。 因为userName是字符串类型,它必然调用resultSet的getString方法。

 这就是TypeHandler的妙用。

自此,无嵌套的结果集映射就全部讲完了。

3. 有嵌套的映射关系

嵌套关系,我们日常开发经常遇到。而mybatis处理嵌套映射,则是映射关系中比较核心的逻辑了。而在mybatis中,针对 一对一的嵌套,和 一对多的嵌套,使用的是不同的标签。association是一对一的嵌套,而 collection 是一对多的嵌套。

针对有嵌套的逻辑,我们走的逻辑肯定也是不一样的,下面我们以 一对多 的嵌套关系为例进行说明,如下:

 代码部分:

3.1  嵌套的行数据 getRowValue方法

开始之前,我先介绍2个缓存,因为我觉得这2个缓存很重要 :

第一个缓存 nestedResultObjects,它是负责缓存行数据的。只要是处理过的行,都会被缓存

 

第二个是缓存所有的结果集数据的,简单的就是它负责存储从数据库中查到的数据。我们最终返回的就是这个list,上层方法拿到这个list处理并且最终返回即可。

ok, 言归正传,下面开始我们的嵌套映射源码分析阶段

1. 至于生成MetaObject的逻辑,它是和无嵌套逻辑一样的,没什么好说的。

2. 对于TUser表的映射,还是走applyPropertyMappings方法,和上面的一样,没什么好说的

3. 嵌套映射,核心在嵌套关系上。

比如TUser表下嵌套Job表,那么TUser表还是原有的逻辑,而Job表会有特有的逻辑来处理,也就是一对一的关系,然后把TUser表放入缓存中,注意此时TUser表已经嵌套了Job表了。

当第二次再来处理的时候,我们会从缓存中拿到之前的TUser表信息,所有就不会再次生成TUser表了,但是Job表示新的,所有我们会按照映射规则再次生成Job对象,放入TUser表的List中。此时,一条TUser表嵌套了多条Job表的数据,这就是一对多的关系

3.1.1 针对TUser表的映射

我们以id为2的数据为例进行分析:

1. 首先,我们进入getRowValue方法内部会映射TUser表,也就是把id为2的数据进行映射。但是,此时不会去映射 Job表的信息

2. 进入处理嵌套关系的映射方法  applyNestedResultMappings 以后,其实就是获取到单独的Job表对象,然后按照之前的逻辑再给映射一遍数据而已。

待我们的Job表初始化完成以后,我们会再次判断这个Job表有没有嵌套关系,如果有嵌套的话,再次进入applyNestedResultMappings方法,进行嵌套类的映射,直到没有映射关系为止。

3. applyNestedResultMappings方法处理完嵌套类的映射以后,我们会进入 linkObjects方法。

4. instantiateCollectionPropertyIfAppropriate 这个方法比较有意思,它是根据映射规则,把TUser表中的字段 jobs 给实例化。而我们TUser表中的 jobs 是一个ArrayList类型的。因此,它也会生成一个ArrayList对象,存储 Job 数据

这个地方,我又要补一下前面的知识了。

Configuration对象负责生成MetaObject,而MetaObject包装的具体是哪一种类型的Bean呢? 这需要根据传入的实例来确定的。此处传入的是是ArrayList,因此会生成一个集合类型的

 既然是集合类型的MetaObject,那么把Job放入MetaObject必然也是ArrayList中的,来看看具体是怎么做到的:

其实,就是简单的把嵌套类 Job放入ArrayList中而已

 5. 最后,还是返回到 getRowValue方法中,把TUser给缓存起来。此时的TUser已经含有1条Job的嵌套数据了。

 3.1.2 再次处理相同的TUser

1. 此时,我们会直接从缓存中获取到TUser信息,因此不会再次生成TUser对象了。但是,TUser嵌套的Job信息则是从数据库刚查出来的,而且是一个嵌套类,因此嵌套处理还时要继续的

来看看第二次进来和第一次进入有何区别:

2.  其实,就是根据当前包装TUser的MetaObject对象,去实例化Jobs这个变量。此时,我们发现TUser对象的 jobs 变量已经被实例化了。就直接拿到这个 jobs变量而已,此处是ArrayList。我们还发现,这个ArrayList里面已经存储了一条Job数据,直接使用这个ArrayList并且把刚查到的另一条关于 Job的数据放入ArrayList中,完成一对多的操作

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值