MyBatis中Collection和Association的底层实现原理

MyBatis中Collection和Association的底层实现原理

Hi 👋, I'm shy

有人见尘埃,有人见星辰

SHY QR Code 技术咨询

引言

在 MyBatis 中,<collection><association> 标签用于处理一对多和一对一的关系。这两个标签在底层通过缓存、对象创建和反射机制,将数据库结果集高效地映射为 Java 对象。本文将重点探讨这两个标签的底层实现原理,并结合实际的数据库示例说明其工作机制。

1. Collection 的底层映射原理

1.1 一对多映射场景

<collection> 标签主要用于表示一对多关系的映射。典型的一对多场景是在一个表中有重复的主对象记录(如用户),但每个主对象包含多个子对象(如订单)。

示例数据库结构

假设我们有以下结果集,表示用户和订单的关系:

user_idusernameorder_idorder_date
1Alice1012023-01-01
1Alice1022023-02-01
2Bob1032023-03-01

这个数据表示,用户 Alice 有两个订单,用户 Bob 有一个订单。我们希望将其映射为一个 User 对象,每个用户对象包含一个订单集合。

MyBatis 映射配置
<resultMap id="userResultMap" type="com.example.User">
    <id property="userId" column="user_id"/>
    <result property="username" column="username"/>
    <collection property="orders" ofType="com.example.Order">
        <id property="orderId" column="order_id"/>
        <result property="orderDate" column="order_date"/>
    </collection>
</resultMap>

在这个映射中,<collection> 标签表示用户对象 User 可能包含多个 Order 对象,ofType 定义了集合中元素的类型。

1.2 底层映射机制

  1. 结果集处理
    当执行 SQL 查询时,MyBatis 会获取完整的结果集。由于用户可能有多个订单,查询结果会包含重复的 user_idusername

  2. 主对象缓存处理
    MyBatis 使用主键 user_id 来判断是否已经创建了对应的 User 对象(如果没有主键, 会使用其他键来模拟唯一键)。

    • 如果 user_id 相同,表示当前行属于同一个用户,则重用该用户对象。
    • 如果 user_id 不同,MyBatis 会创建新的 User 对象。
  3. 集合属性映射
    对于每一行的订单信息(order_idorder_date),MyBatis 会为当前的用户创建新的 Order 对象,并将其添加到用户的 orders 集合中。

  4. 对象重用与集合管理
    通过缓存机制,MyBatis 确保每个用户只创建一次,而订单则根据不同的 order_id 创建。对于相同的用户,每个订单行都会被添加到 orders 集合中。

底层逻辑代码示例(伪代码)
// 查询用户缓存处理
if (!cache.containsKey(userId)) {
    User user = new User();
    user.setUserId(resultSet.getInt("user_id"));
    user.setUsername(resultSet.getString("username"));
    cache.put(userId, user);
}

// 处理订单集合
Order order = new Order();
order.setOrderId(resultSet.getInt("order_id"));
order.setOrderDate(resultSet.getDate("order_date"));

// 将订单添加到用户的集合
user.getOrders().add(order);

MyBatis 会缓存用户对象,并通过 getOrders().add(order) 方法将每个新创建的订单对象加入到用户的订单集合中。

2. Association 的底层映射原理

2.1 一对一映射场景

<association> 标签用于处理一对一或多对一的映射。在这种场景下,通常我们希望将两个表的结果组合为一个主对象和一个关联对象。例如,用户和用户详情是一对一的关系。

示例数据库结构

假设我们有以下结果集,表示用户及其详细信息:

user_idusernamedetail_idageaddress
1Alice125Wonderland
2Bob230Wonderland

这个数据表示,每个用户有一条与之关联的详细信息记录。我们希望将其映射为 User 对象,其中包含一个 UserDetail 对象。

MyBatis 映射配置
<resultMap id="userWithDetailResultMap" type="com.example.User">
    <id property="userId" column="user_id"/>
    <result property="username" column="username"/>
    <association property="detail" javaType="com.example.UserDetail">
        <id property="detailId" column="detail_id"/>
        <result property="age" column="age"/>
        <result property="address" column="address"/>
    </association>
</resultMap>

在这个映射中,<association> 标签用于将用户与详细信息关联起来,javaType 指定了 UserDetail 对象的类型。

2.2 底层映射机制

  1. 主对象创建与缓存
    当执行查询时,MyBatis 会首先根据 user_id 创建或查找缓存中的用户对象。类似于 <collection>,如果用户对象已经存在,则不会重新创建。

  2. 关联对象的映射
    对于每一行,MyBatis 根据 detail_id 创建 UserDetail 对象,并通过 MetaObject 机制,将查询结果的 ageaddress 列映射到 UserDetail 对象中。

  3. 关联对象赋值
    一旦 UserDetail 对象创建完成,MyBatis 会将其赋值给 User 对象的 detail 属性。这是通过反射完成的。

底层逻辑代码示例(伪代码)
// 用户缓存处理
User user = cache.get(userId);

// 创建并映射用户详细信息
UserDetail detail = new UserDetail();
detail.setDetailId(resultSet.getInt("detail_id"));
detail.setAge(resultSet.getInt("age"));
detail.setAddress(resultSet.getString("address"));

// 将详细信息赋值给用户对象
user.setDetail(detail);

MyBatis 在映射时会通过 MetaObject 访问 User 对象的 detail 属性,并使用反射为其赋值。这个过程使得每个用户对象都能够正确关联其详细信息。

3. 总结

MyBatis 中的 <collection><association> 标签通过缓存、反射与对象创建机制,完成数据库结果集到 Java 对象的映射。在处理一对多和一对一关系时,这两个标签的底层机制可以高效地组织复杂的对象结构。

  • <collection> 标签:通过主对象的缓存和子对象集合的动态添加,实现了复杂的一对多关系的映射。
  • <association> 标签:通过关联对象的创建和属性映射,实现了一对一或多对一的关联映射。

理解这些底层机制能够帮助开发者优化查询性能,并更好地设计数据结构,充分发挥 MyBatis 的 ORM 功能。


欢迎评论区沟通交流~

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

以系统工程为指导的军品设计、开发与管理常用方法培训

课程背景&#xff1a; 产品开发和产品管理是组织经营战略的核心&#xff0c;而经营战略又为组织的创新战略、产品开发和产品管理提供了环境和方向。使命、愿景与核心价值观对于产品开发的聚焦点和管理方式都具有十分重要的作用。产品开发通常被称为组织的“血液”&#xff0c;…

node.js框架StrongLoop快速入门实战

目录 一、StrongLoop框架简介 二、安装StrongLoop框架 三、创建项目my-loopback-project 四、项目布局和结构 五、配置连接mysql数据库 六、实现自动生成api接口 一、StrongLoop框架简介 StrongLoop是一个强大的框架&#xff0c;它基于Node.js构建&#xff0c;几乎涵盖了…

《信息系统安全》课程实验指导

第1关&#xff1a;实验一&#xff1a;古典密码算法---代换技术 任务描述 本关任务&#xff1a;了解古典密码体制技术中的代换技术&#xff0c;并编程实现代换密码的加解密功能。 注意所有明文字符为26个小写字母&#xff0c;也就是说字母表为26个小写字母。 相关知识 为了完…

【开源免费】基于SpringBoot+Vue.JS高校心理教育辅导系统(JAVA毕业设计)

本文项目编号 T 031 &#xff0c;文末自助获取源码 \color{red}{T031&#xff0c;文末自助获取源码} T031&#xff0c;文末自助获取源码 目录 一、系统介绍二、演示录屏三、启动教程四、功能截图五、文案资料5.1 选题背景5.2 国内外研究现状5.3 可行性分析5.4 用例设计 六、核…

JEE 设计模式

Java 数据访问对象模式 Java设计模式 - 数据访问对象模式 数据访问对象模式或DAO模式将数据访问API与高级业务服务分离。 DAO模式通常具有以下接口和类。 数据访问对象接口定义模型对象的标准操作。 数据访问对象类实现以上接口。可能有多个实现&#xff0c;例如&#xff0c…

LVGL学习

注&#xff1a;本文使用的lvgl-release-v8.3版本&#xff0c;其它版本可能稍有不同。 01 LVGL模拟器配置 day01-02_课程介绍_哔哩哔哩_bilibili LVGL开发教程 (yuque.com) 如果按照上述视频和文档中配置不成功的话&#xff0c;直接重装VsCode&#xff0c;我的就是重装以后就…

Git提交有乱码

服务器提交记录如图 可知application.properties中文注释拉黄线 &#xff0c;提示Unsupported characters for the charset ISO-8859-1 打开settings - Editor - File Encodings 因为我们项目的其他文件都是UTF-8&#xff0c;所以&#xff0c;我们将默认值都改成UTF-8 然后…

打造民国风格炫酷个人网页:用HTML和CSS3传递民国风韵

附源码&#xff01;&#xff01;&#xff01; 感谢支持 小弟不断创作网站demo感兴趣的可以关注支持一下 对了 俺在结尾带上了自己用的 背景 大家可以尝试换一下效果更好哦~~~ 如何创建一个民国风格的炫酷网页 在这篇博客中&#xff0c;我们将展示如何制作一个结合民国风格和…

【无标题】Efinity 0基础进行流水灯项目撰写(FPGA)

文章目录 前言一、定义概念 缩写1. 二、性质1.2. 三、使用步骤编译常见错误1. 没加分号2. end 写多了 编译成功的标志总结参考文献 前言 数电课设 使用 FPGAIDE 使用 Efinity 一、定义概念 缩写 1. 二、性质 1. 2. 三、使用步骤 python代码块matlab代码块c代码块编译…

Vue3+CesiumJS相机定位camera

new Cesium.Camera (scene) 摄像机由位置&#xff0c;方向和视锥台定义。 方向与视图形成正交基准&#xff0c;上和右视图x上单位矢量。 视锥由6个平面定义。每个平面都由 Cartesian4 对象表示&#xff0c;其中x&#xff0c;y和z分量定义垂直于平面的单位矢量&#xff0c;w分量…

C++《类和对象》(下)

在之前类和对象&#xff08;中&#xff09;我们学习了类当中的6大默认成员函数&#xff0c;我们了解了6大成员函数的结构特征和特点以及在不同情况各个成员函数是如何调用的&#xff0c;那么接下来我们在本篇当中将继续学习之前在学习构造函数中未了解的初始化列表&#xff0c;…

【Python】生成图片验证码

1. 首先安装第三方库PIL&#xff08;图像处理库&#xff09; pip install pillow 2. 编写生成验证码代码 这里字体 SimHei.ttf 文件要放在该文件目录下。 import random from PIL import Image, ImageDraw, ImageFont, ImageFilterdef check_code(width128, height30, char…

ros学习笔记.4 Path Planning Part 2 (避障)

避障是如何工作的什么是局部规划器&#xff1f;什么是局部成本图&#xff1f;路径规划回顾如何使用动态重新配置和其他 Rviz 工具 局部规划器 一旦全局规划器计算出要遵循的路径&#xff0c;该路径就会发送给局部规划器。然后&#xff0c;局部规划器将执行全局规划的每个部分&…

比较stl库的ostringstream与Qt的QString::arg(),QString::number()

需求&#xff1a; 显示一个float或者double类型的数&#xff0c;要求小数点后的数字位数为定值。 考虑STL库的ostringstream或者Qt的QString::arg(), number 对于stringstream,使用比较繁琐&#xff0c;要联合使用std::fixed和std::setprecision才能实现固定小数位数显示&am…

UE5-俯视角色移动(蓝图)01

效果如下&#xff1a; 蓝图节点如下&#xff1a; 使用示例自带的移动蓝图&#xff0c;发现角色只能平移&#xff0c;不会转向。必须勾选以下选项&#xff1a; 点击蓝图-》组件-》SpringArm节点。在细节中找到摄像机设置&#xff0c;勾选以下&#xff1a; 在 点击蓝图-》组件-…

PowerShell install 一键部署Oracle21c-xe

Oracle21c-xe前言 无论您是开发人员、DBA、数据科学家、教育工作者,还是仅仅对数据库感兴趣,Oracle Database Express Edition (XE) 都是理想的入门方式。它是全球企业可依赖的强大的 Oracle Database,提供简单的下载、易于使用和功能齐全的体验。您可以在任何环境中使用该…

Qt多语言/多语种详细开发教程

Qt作为跨平台的开发工具&#xff0c;早已应用到各行各业的软件开发中。 今天讲讲&#xff0c;Qt开发的正序怎么做多语言开发。就是说&#xff0c;你设置中文&#xff0c;就中文显示&#xff1b;设置英语就英文显示&#xff0c;设置繁体就繁体显示&#xff0c;设置发育就显示法语…

Vue3+TS项目给el-button统一封装一个点击后转圈效果的钩子函数按钮防抖

前言 每个按钮都要单独定义一个loading变量&#xff0c;并且在接口请求前修改为true&#xff0c;接口响应后再修改为false&#xff0c;封装后这段重复的逻辑就可以统一管理不用每次都写一遍了。 效果 新建一个公共的src\common.ts import { ref } from "vue"expor…

Azure web app has no access to openai private endpoint in virtual network

题意&#xff1a;"Azure Web 应用无法访问虚拟网络中的 OpenAI 私有端点。" 问题背景&#xff1a; I am trying to host a web application similar to a private ChatGPT instance within a secluded virtual network, ensuring that theres no external internet …

服务器环境搭建-5 Nexus搭建与使用介绍

背景 本文介绍nexus的安装、配置和使用&#xff0c;之后通过案例的方式演示使用过程。 1.下载和安装 本文使用Nexus 3.x版本进行演示 下载地址&#xff1a;Download Nexus Repository OSS | Sonatype 国外网站下载速度较慢&#xff0c;也可以通过百度网盘下载(提取码:9999): …