2.1MyBatis——ORM对象关系映射

news2024/10/5 14:23:47

2.1MyBatis——ORM对象关系映射

  • 1. 验证映射配置
  • 2.ResultType和ResultMap
    • 2.1ResultMap是最终的ORM依据
    • 2.2ResultType和ResultMap的使用区别
  • 3.具体的转换逻辑
    • 3.1 TypeHandle类型转换
  • 5.总结

概括的说,MyBatis中,对于映射关系的声明是由开发者在xml文件手动完成的。比如对查询方法而言,你需要显式声明ResultType或ResultMap,这里其实就是在定义数据库字段和Java属性之间的映射关系。

下面我们以简单的查询方法为例,探索MyBatis如何将数据库字段转换为具体对象的字段属性,即ORM的具体过程。
首先我们先验证ORM这一过程确实存在。

1. 验证映射配置

<!--方法1-->
<select id="queryWithoutType">
	select * from user where id = #{id}
</select>
<!--方法2-->
<select id="queryWithReturnType" resultType="org.wyy.dto.User">
	select * from user where id = #{id}
</select>

<resultMap id="customMap" type="org.wyy.dto.User"></resultMap>
<!--方法3-->
<select id="queryWithReturnMap" resultMap="customMap">
	select * from user where id = #{id}
</select>

这里我们定义三个相同逻辑的方法,方法1不声明映射关系。分别运行三个方法,方法2和方法3正常执行,方法1抛出异常如下:

org.mybatis.spring.MyBatisSystemException: 
nested exception is org.apache.ibatis.executor.ExecutorException: 
A query was run and no Result Maps were found for the Mapped Statement 
'org.wyy.mapper.UserMapper.queryWithoutType'.  
It's likely that neither a Result Type nor a Result Map was specified.

说明Mybatis中,ORM的映射转换需要在xml的每个方法中手动配置,否则无法进行查询。

2.ResultType和ResultMap

对查询方法未做任何配置时,异常提示It's likely that neither a Result Type nor a Result Map was specified.,即至少需要ResultTypeResultMap其中一个,那么它们有什么关系呢?看一下源码:

在这里插入图片描述

2.1ResultMap是最终的ORM依据

从上图可以看出,当ResultMap为空但ResultType不为空时(即<select>标签配置了resultType属性),XxMapper.xml加载后会Mybatis默认创建一个后缀为-InlineResultMap对象,所以MyBatis中映射转换最终参照的都是ResultMap对象

2.2ResultType和ResultMap的使用区别

既然最终都是使用ResultMap对象进行关系映射,为什么还要设计ResultType呢?它们在使用时的区别又是什么呢?
先看下ResultMap对象的结构:

private Configuration configuration;
private String id;
private Class<?> type;
private List<ResultMapping> resultMappings;
private List<ResultMapping> idResultMappings;
private List<ResultMapping> constructorResultMappings;
private List<ResultMapping> propertyResultMappings;
private Set<String> mappedColumns;
private Set<String> mappedProperties;
private Discriminator discriminator;
private boolean hasNestedResultMaps;
private boolean hasNestedQueries;
private Boolean autoMapping;

加载:前面的查询我们提到,在MyBatis加载Mapper.xml文件时,如果某个查询方法定义了resultType属性,那么会为其自动生成ResultMap对象,这个ResultMap其实相当简单,只有id 和 type属性。
执行:当查询方法被调用时,在ResultSetHandler中会进行如下判断:

public void handleRowValues(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping) throws SQLException {
    if (resultMap.hasNestedResultMaps()) {
      ensureNoRowBounds();
      checkResultHandler();
      // 嵌套类型
      handleRowValuesForNestedResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);
    } else {
    // 简单类型
      handleRowValuesForSimpleResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);
    }
  }

结合ResultMap对象的属性ResultType自动生成的简单ResultMap对象,以及这里处理结果集的判断,可以看出,MyBatis中将结果集映射进行了分类:简单和复杂嵌套。

  • 对于简单的ResultMap,直接使用<select>标签声明的映射类型(这里是org.wyy.dto.User)创建映射器Reflector,并使用MyBatis内置的类型处理器TypeHandler(如StringTypeHandler、LongTypeHandler等)进行处理
  • 对于存在嵌套的类型,则需要通过自定义的ResultMap进行列名和字段的映射绑定,以及指定所需的类型转换器

区别和使用:

  • 对单表查询而言,如果数据库字段和对象的属性名一致,没必编写映射关系,直接使用ResultType即可。这也是为什么即使ResultType最终会生成ResultMap,却依然保留ResultType的原因:使用ResultType可以简化配置。
  • 对于查询结果集不能与对象属性一一匹配的情况,则必须通过显示定义ResultMap来声明映射关系,特殊类型可能还需要定义类型转换器
<resultMap id="customMap" type="org.wyy.dto.User">
	<result column="" jdbcType="VARCHAR" 
			property="" javaType="" 
			typeHandler="org.apache.ibatis.type.StringTypeHandler" />
</resultMap>

3.具体的转换逻辑

有了前面的描述,我们知道,数据库列名和对象属性之间的映射是通过ResultMap维护的。有了这层映射关系,如果是我们,该如何将数据从结果集装填到对象中呢?

  1. 获取当前查询方法的ResultMap,里面包含列和属性的对应关系
  2. 使用列名获取结果集中对应的数据
  3. 根据映射关系,将获取到的列数据赋值给对象的相应属性


    其实MyBatis中也是这样做的:
private boolean applyAutomaticMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject, String columnPrefix) throws SQLException {
	// 映射关系的获取
    List<UnMappedColumnAutoMapping> autoMapping = createAutomaticMappings(rsw, resultMap, metaObject, columnPrefix);
    boolean foundValues = false;
    if (!autoMapping.isEmpty()) {
      // 每一列和属性的映射关系,分别遍历
      for (UnMappedColumnAutoMapping mapping : autoMapping) {
      	// 通过类型处理器typeHandler,从结果集中获取列的值
        final Object value = mapping.typeHandler.getResult(rsw.getResultSet(), mapping.column);
        if (value != null) {
          foundValues = true;
        }
        if (value != null || (configuration.isCallSettersOnNulls() && !mapping.primitive)) {
          // 将取出的列的value设置给对应的对象属性,完成columen --> property的赋值
          metaObject.setValue(mapping.property, value);
        }
      }
    }
    return foundValues;
  }

3.1 TypeHandle类型转换

上面代码可以看到,从结果集中获取值并转化是由类型处理器完成的。MyBatis中内置了常用的类型处理器,用来完成java type 和jdbc type之间的转换

// java type + jdbc type + handler
  public <T> void register(Class<T> type, JdbcType jdbcType, TypeHandler<? extends T> handler) {
    register((Type) type, jdbcType, handler);
  }

// 内部注册
public TypeHandlerRegistry() {
    register(Boolean.class, new BooleanTypeHandler());
    register(boolean.class, new BooleanTypeHandler());
    register(JdbcType.BOOLEAN, new BooleanTypeHandler());
    register(JdbcType.BIT, new BooleanTypeHandler());
    ...
}

对于无法转换的类型,则可以通过自定义类型转换器进行扩展:

// column varchar  --> java property LocalDate
<resultMap id="customMap" type="org.wyy.dto.User">
	<result column="update_time" property="updateTime" typeHandler="org.wyy.typeHandler.CustomTypeHandler"/>
</resultMap>

@MappedTypes(LocalDate.class)
public class CustomTypeHandler extends BaseTypeHandler<LocalDate> {}

5.总结

  1. . Mybatis中ORM是我们通过ResultType或ResultMap手动完成关系映射的,所以ResultType和ResultMap至少需要一个,否则报错;
  2. ResultType属性简化了ORM配置,但复杂对象或对象嵌套,则必须使用ResultMap;
  3. 以查询为例,转换的流程是先查询映射关系,再查询具体列的值,然后通过类型转换器转换为Java属性,最后赋值;
  4. MyBatis内置了许多类型转换器,使得大部分场景下不需要显式配置。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2190004.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

“2024年最流行的10个前端框架”

大多数时候&#xff0c;前端开发人员需要使用一组组合语言来构建他们的前端 Web 应用程序。 HTML 负责网页中的基本布局&#xff0c;CSS 管理视觉格式和结构&#xff0c;JavaScript 用于维护交互性和功能。在这篇文章中&#xff0c;我们将了解最好的前端框架&#xff0c;这些框…

FL Studio 24.1.2.4381中文版免费下载及FL Studio 24最新使用学习教程

家好呀&#xff0c;作为一个资深的音乐爱好者和制作人&#xff0c;今天我要安利一个我最近超级痴迷的数字音频工作站软件——FL Studio24.1.2.4381中文版。这款产品可是让我的音乐创作之路如虎添翼&#xff0c;快来跟我一起看看它的炫酷功能吧&#xff01; 最近接到很多小伙伴的…

2024 ciscn WP

一、MISC 1.火锅链观光打卡 打开后连接自己的钱包&#xff0c;然后点击开始游戏&#xff0c;答题八次后点击获取NFT&#xff0c;得到有flag的图片 没什么多说的&#xff0c;知识问答题 兑换 NFT Flag{y0u_ar3_hotpot_K1ng} 2.Power Trajectory Diagram 方法1&#xff1a; 使用p…

操作系统实验之银行算法

一、实验目的 采用高级语言编写一个动态分配系统资源的程序&#xff0c;模拟死锁现象&#xff0c;观察死锁发生的条件&#xff0c;并采用适当的算法&#xff0c;有效地防止死锁的发生。 二、实验内容 本次实验采用银行算法防止死锁的发生。设有3个并发进程共享10个系统资源。在…

1c语言基础

1.关键字 一、数据类型关键字 A基本数据类型&#xff08;5个&#xff09; void&#xff1a;声明函数无返回值或无参数&#xff0c;声明无类型指针&#xff0c;显式丢弃运算结果char&#xff1a;字符型类型数据&#xff0c;属于整型数据的一种int&#xff1a;整型数据&#x…

Ollama 运行视觉语言模型LLaVA

Ollama的LLaVA&#xff08;大型语言和视觉助手&#xff09;模型集已更新至 1.6 版&#xff0c;支持&#xff1a; 更高的图像分辨率&#xff1a;支持高达 4 倍的像素&#xff0c;使模型能够掌握更多细节。改进的文本识别和推理能力&#xff1a;在附加文档、图表和图表数据集上进…

Github界面学习

之前并没有使用到其他功能大多数是看代码&#xff0c;然后看discussion&#xff1b; now,在做毕设的时候发现了一个gymnasium关于异步环境的bug&#xff0c;查看github发现已经被修复了&#xff1b; 因此希望学习一下修复者是在哪个module修复以及如何修复以及提交代码&#…

Spring Boot框架在大学生就业招聘中的应用

3系统分析 3.1可行性分析 通过对本大学生就业招聘系统实行的目的初步调查和分析&#xff0c;提出可行性方案并对其一一进行论证。我们在这里主要从技术可行性、经济可行性、操作可行性等方面进行分析。 3.1.1技术可行性 本大学生就业招聘系统采用JAVA作为开发语言&#xff0c;S…

kaggle实战3RossmanStore商店销售额预测XgBoost解决回归问题案例1

kaggle实战2信用卡反欺诈逻辑回归模型案例1 数据集下载地址 https://download.csdn.net/download/AnalogElectronic/89844637 https://tianchi.aliyun.com/dataset/89785 加载数据 #预测销售额 回归问题 import numpy as np import pandas as pd import matplotlib.pyplot a…

无神论文解读之ControlNet:Adding Conditional Control to Text-to-Image Diffusion Models

一、什么是ControlNet ControlNet是一种能够控制模型生成内容的方法&#xff0c;能够对文生图等模型添加限制信息&#xff08;边缘、深度图、法向量图、姿势点图等&#xff09;&#xff0c;在当今生成比较火的时代很流行。 这种方法使得能够直接提供空间信息控制图片以更细粒…

招联2025校招内推倒计时

【投递方式】 直接扫下方二维码&#xff0c;或点击内推官网https://wecruit.hotjob.cn/SU61025e262f9d247b98e0a2c2/mc/position/campus&#xff0c;使用内推码 igcefb 投递&#xff09; 【招聘岗位】 后台开发 前端开发 数据开发 数据运营 算法开发 技术运维 软件测试 产品策…

【课程学习】随机过程之泊松过程

随机过程之泊松过程 泊松分布泊松过程 泊松分布 二项分布是离散性的分布&#xff0c;泊松分布是把二项分布取n趋于无穷得到的连续分布。也就是在一段时间内不停的观察某件事情发生的次数。 如&#xff1a;一个小时内观察一段路上经过行人的数目&#xff0c;如果每个半个小时观…

nginx和gateway的关系和区别

在技术选型时&#xff0c;选择 Nginx 和 Spring Cloud Gateway&#xff08;或简称为 Gateway&#xff09;主要取决于具体应用场景和技术需求。下面是两者的一些关键差异和适用场景。 一、Nginx 概念 Nginx 是一个高性能的 Web 服务器和反向代理服务器&#xff0c;常被用作静…

智能手表(Smart Watch)项目

文章目录 前言一、智能手表&#xff08;Smart Watch&#xff09;简介二、系统组成三、软件框架四、IAP_F411 App4.1 MDK工程结构4.2 设计思路 五、Smart Watch App5.1 MDK工程结构5.2 片上外设5.3 板载驱动BSP5.4 硬件访问机制-HWDataAccess5.4.1 LVGL仿真和MDK工程的互相移植5…

CSRF | CSRF 漏洞介绍

关注这个漏洞的其他相关笔记&#xff1a;CSRF 漏洞 - 学习手册-CSDN博客 0x01&#xff1a;CSRF 漏洞简介 CSRF&#xff08;Cross-Site request forgery&#xff0c;跨站请求伪造&#xff09;也被称为 One Click Attack 或者 Session Riding&#xff0c;通常缩写为 CSRF 或者 X…

【Java】IntelliJ IDEA开发环境安装

一、下载 官方地址&#xff1a;https://www.jetbrains.com/idea/ 点击Download直接下载 二、安装 双击安装包&#xff0c;点击Next 选择安装路径&#xff0c;点击Next 勾选安装内容 安装完成。 三、创建项目 打开IDEA&#xff0c;填写项目名称&#xff0c;选择项目安装路径…

S7-200 SMART的数据类型说明

S7-200 SMART的数据主要分为&#xff1a; 与实际输入/输出信号相关的输入/输出映象区&#xff1a; I&#xff1a;数字量输入&#xff08;DI&#xff09;Q&#xff1a;数字量输出&#xff08;DO&#xff09;AI&#xff1a;模拟量输入AQ&#xff1a;模拟量输出 内部数据存储区…

STM32 Hal库SDIO在FATFS使用下的函数调用关系

STM32 Hal库SDIO在FATFS使用下的函数调用关系 本文并不将FATFS的相关接口操作&#xff0c;而是将HAL在使用FATFS通过SDIO外设管理SD卡时&#xff0c;内部函数的调用逻辑&#xff0c;有助于当我们使用CUBEMX生成FATFS读取SD卡的代码时无法运行时Debug。本文也会说明一些可能出现…

如何编写一个优雅的commit message

在Git中&#xff0c;git commit 命令扮演着至关重要的角色。它的主要作用是将暂存区&#xff08;staging area&#xff09;里的改动内容提交到本地仓库&#xff08;repository&#xff09;中&#xff0c;形成一个新的版本或提交&#xff08;commit&#xff09;。这个过程是 Git…

渗透测试入门学习——使用python脚本自动识别图片验证码,OCR技术初体验

写在前面 由于验证码在服务端生成后存储在服务器的session中&#xff0c;而标用于标识用户身份的sessionid存在于用户cookie中 所以本次识别验证码时需要用requests.session()创建会话对象&#xff0c;模拟真实的浏览器行为&#xff0c;保持与服务器的会话才能获取登录时服务…