Mybatis 的关联映射(一对一,一对多,多对多)
前言
在前面我们已经了解了,mybatis 的基本用法,动态SQL,学会使用mybatis 来操作数据库。但这些主要操作还是针对 单表实现的。在实际的开发中,对数据库的操作,常常涉及多张表。
因此本篇博客的目标:通过mybatis 提供的关联映射,建立表与表之间的关系,实现多表的数据操作。
关联映射的概述
在关系型数据库中,表与表之间存在3 种关联映射关系,分别是 一对一,一对多/多对一,和多对多
1. 一对一(One-to-One)
一对一关系是指一个表中的每个记录与另一个表中的一个记录相关联,且这种关联是唯一的。例如:
一个学生只能有一个学生证,一个学生证只属于一个学生。
一个用户只能有一个个人资料,一个个人资料只属于一个用户。
在数据库设计中,一对一关系可以通过以下方式实现:
主键关联:将一个表的主键作为外键放在另一个表中。
联合主键:将两个表的主键合并为一个联合主键,存储在一张表中。
2. 一对多/多对一(One-to-Many/Many-to-One)
一对多关系是指一个表中的一个记录可以与另一个表中的多个记录相关联,而另一个表中的每个记录只能与第一个表中的一个记录相关联。例如:
一个部门可以有多个员工,但每个员工只能属于一个部门。
一个作者可以写多本书,但每本书只能由一个作者创作。
在数据库设计中,一对多关系通常通过外键来实现:
在“多”的一方的表中添加一个外键字段,指向“一”的一方的主键字段。
3. 多对多(Many-to-Many)
多对多关系是指一个表中的多个记录可以与另一个表中的多个记录相关联。例如:
一个学生可以选修多门课程,一门课程也可以被多个学生选修。
一个作者可以写多本书,一本书也可以由多个作者共同创作。
注意
在数据库设计中,多对多关系通常通过一个**关联表(中间表)**来实现:
关联表包含两个表的主键作为外键字段,用于建立多对多关系。
例如,对于学生和课程的多对多关系,可以创建一个选课表,包含学生ID和课程ID作为外键字段。
一对一查询
应用场景
例如 表示 一个人 只能有一个身份证,同时一个身份证也只对应一个人
重点
在学习 一对一查询 时,核心是学习使用 <association>元素 来处理 一对 对关联关系。 <association>元素 提供了一系列 属性用于维护数据表之间的关系
<association>元素 常用的属性
| 属性 | 说明 |
| property | 用于指定映射到的实体类的属性,与表字段一一对应 |
| Column | 用于指定表中的对应的字段 |
| javaType | 用于指定映射到实体对象的属性 |
| jdbcType | 用于指定数据表中对应的字段类型 |
| fetchType | 用于指定在关联查询时是否启用延迟加载。fetchType属性 有lazy,eager两个属性值,默认为lazy(默认关联映射延迟加载) |
| select | 用于指定引入嵌套查询的子SQL语句,该属性用于关联映射的前提查询 |
| autoMapper | 用于指定是否自动映射 |
| typeHander | 用于指定一个类型处理器 |
<association>元素 是<resultMap>元素的子元素,它有两种配置方式 :嵌套查询方式,嵌套结果方式。
嵌套查询方式,嵌套结果方式的区别
我理解 嵌套查询方式是多步走,而不是一步到位。例如 你写一个 复合sql语句【相当于sql 嵌套着其他的sql 语句】,去查表中的数据,现在是把这个sql 语句拆开,通过表之间的关系 ,一个个去查,最好得到结果。
样例
<!-- 嵌套查询方式--><association property="card" column="card_id" javaType="fs.pojo.IdCard" select="fs.mapper.IdCardMapper.findCodeById"/>嵌套结果方式,则是一步到位。通过使用一个复合的sql 语句【相当于sql 嵌套着其他的sql 语句】得到最终结果。
样例
<!-- 嵌套结果查询--><association property="card" javaType="fs.pojo.IdCard" ><id property="id" column="card_id"/><result property="code" column="CODE"/></association>
demo(案例)
项目准备
数据库中 tb_person 表,tb_idcard 表
实体类 IdCard 类,Person 类
mybatis -config 配置文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration><properties resource="db.properties"></properties> <settings><!-- environment 是一个环境,里面包含一个事务管理器,一个数据源 --><environments default="development"><environment id="development"><transactionManager type="JDBC"></transactionManager><dataSource type="POOLED"><!-- 配置数据源信息,主要有 数据库驱动,数据库连接地址,数据库用户名,数据库密码等 --><property name="driver" value="${driverClass}"></property><property name="url" value="${jdbcUrl}"></property><property name="username" value="${username}"></property><property name="password" value="${password}"></property></dataSource></environment></environments><mappers><!-- 使用mapper 标签 指定mapper映射文件--><mapper resource="mapper/PersonMapper.xml"/><mapper resource="mapper/IdCardMapper.xml"/><mapper resource="mapper/UserMapper.xml"/><mapper resource="mapper/OrdersMapper.xml"/><mapper resource="mapper/ProductMapper.xml"/></mappers>
</configuration>
问题:当输入 id=1时,查询person 人的具体信息包括个人身份证信息
PersonMapper 接口
// 根据id查询Person findPersonById(Integer id);Person findPersonById2(Integer id);
PersonMapper.xml 映射文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="fs.mapper.PersonMapper">
// 需要针对 数据库做的操作【查询,修改,删除,插入】
</mapper>
嵌套查询方式【多步到位】
<select id="findPersonById" parameterType="int" resultMap="card">select * from tb_person where id = #{id}
</select><resultMap id="card" type="fs.pojo.Person"><id property="id" column="id"/><result property="name" column="name"/><result property="sex" column="sex"/><result property="age" column="age"/>
<!-- 嵌套查询方式--><association property="card" column="card_id" javaType="fs.pojo.IdCard"select="fs.mapper.IdCardMapper.findCodeById"/></resultMap>
嵌套查询方式 接口的findCodeById 方法和IdCardMapper.xml映射文件
- 接口的findCodeById 方法

- IdCardMapper.xml映射文件

嵌套结果方式【一步到位】
<select id="findPersonById2" parameterType="int" resultMap="card2">select p.*, c.code from tb_person p , tb_idcard c where p.id = #{id} and p.card_id = c.id</select><resultMap id="card2" type="fs.pojo.Person"><id property="id" column="id"/><result property="name" column="name"/><result property="sex" column="sex"/><result property="age" column="age"/>
<!-- 嵌套结果查询--><association property="card" javaType="fs.pojo.IdCard" ><id property="id" column="card_id"/><result property="code" column="CODE"/></association></resultMap>
一对多查询
应用场景
与一对一的关联相比,更多关联关系是一对多(或多对一)例如 一个用户 可以有多个订单,多个订单也可以归一个用户所有。
重点使用<collection>元素来处理一对多关联关系。
<collection>元素 和<association>元素的关系
1 <collection>元素 的属性 大部分与 <association> 元素 相同,但其还包含一个特殊属性--ofType
ofType 与javaType属性相对应,用于指定实体类对象中集合类属性所包含的元素类型【集合中存储的实体类对象类型】
2 与 <association> 元素 相同 ,也是<resultMap>元素的子元素,<collection> 元素 也嵌套查询和嵌套结果两者配置方式
demo(案例)
项目准备
数据库 中 tb_user用户表 ,tb_order 订单表
实体类 User 用户 类,Orders订单类
问题:当输入用户 id=1,时获得 该用户所有的订单情况
UserMapper接口
package fs.mapper;import fs.pojo.User;public interface UserMapper {User findUserWithOrders(Integer id);
}
UserMapper.xml 映射文件
-
嵌套结果查询方式【一步到位】
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="fs.mapper.UserMapper"><select id="findUserWithOrders" parameterType="int" resultMap="orders">select u.*,o.id as orders_id,o.number from tb_user u, tb_orders owhere u.id = o.user_id and u.id = #{id}</select><resultMap id="orders" type="fs.pojo.User"><id property="id" column="id"/><result property="username" column="username"/><result property="address" column="address"/><collection property="orders" ofType="fs.pojo.Orders"><id property="id" column="orders_id"/><result property="number" column="number"/></collection></resultMap>
</mapper>
多对多查询
应用场景
多对多查询 和一对多查询,在现实生活也是非常常见的。以订单和商品为例,一个订单可以包含多种商品,而一种商品又可以属于多种订单中,订单和商品就是典型的多对多的关系。
重点使用<collection>元素来处理多对多关联关系。
demo(案例)
项目准备
数据库中 tb_orders 订单表 ,tb_product 商品表
中间表 tb_ordersitem
实体类 Product用户 类,Orders订单类
问题:当输入 订单 id=1 时,查询 该订单中所有的商品信息
OrderMapper 接口
package fs.mapper;import fs.pojo.Orders;
public interface OrdersMapper {
Orders findOrdersWithProduct(Integer id);Orders findOrdersWithProduct1(Integer id);
}
OrderMapper 映射文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="fs.mapper.OrdersMapper">
// 各自数据库的操作
</mapper>
嵌套查询方式【多步到位】
<select id="findOrdersWithProduct1" parameterType="int" resultMap="orders">select * from tb_orders where id=#{id};</select><resultMap id="orders" type="fs.pojo.Orders"><id property="id" column="id"/><result property="number" column="number"/><collection property="productList" column="id" ofType="fs.pojo.Product" select="fs.mapper.ProductMapper.findProductById"></collection></resultMap>
嵌套查询方式 接口的findProductById 方法和ProductMapper.xml映射文件
- ProductMapper 接口

- ProductMapper.xml 映射文件

嵌套结果方式【一步到位】
- 没有给 tb_product 表的 id 字段 添加别名为 pid 之前
产生问题
当两者关联的表存在相同的字段时,在执行sql 查询 后,会因为tb_order表的id 字段和tb_product 的 id字段 相同,导致 查询结果在映射到product 实体类对象时,后面的product 对象始终会把前面的product 对象覆盖掉。本来应该查询多个 product对象信息,但最好打印只有 1个【最好一个product对象信息】
运行截图
如果给 tb_product 表的 id 字段 添加别名 或者 给 tb_orders 表 的 id 字段添加别名
- 在这里我是给 tb_product 表的 id 字段 添加别名 为 pid
运行截图
- 最好确实出现了3 个product 对象的具体信息
相关文章:
Mybatis 的关联映射(一对一,一对多,多对多)
前言 在前面我们已经了解了,mybatis 的基本用法,动态SQL,学会使用mybatis 来操作数据库。但这些主要操作还是针对 单表实现的。在实际的开发中,对数据库的操作,常常涉及多张表。 因此本篇博客的目标:通过my…...
深度解码!清华大学第六弹《AIGC发展研究3.0版》
在Grok3与GPT-4.5相继发布之际,《AIGC发展研究3.0版》的重磅报告——这份长达200页的行业圣经,不仅预测了2025年AI技术爆发点,更将「天人合一」的东方智慧融入AI伦理建构,堪称数字时代的《道德经》。 文档:清华大学第…...
/dev/console文件详解
/dev/console概览 /dev/console 是 Linux 系统中的一个特殊设备文件,通常用于与系统的控制台进行交互。它的作用和特点如下: 1. 作用 init 进程(PID 1)和某些系统服务在启动时会使用 /dev/console 进行日志输出,以确…...
ProfibusDP主站转ModbusTCP网关如何进行数据互换
ProfibusDP主站转ModbusTCP网关如何进行数据互换 在现代工业自动化领域,通信协议的多样性和复杂性不断增加。Profibus DP作为一种经典的现场总线标准,广泛应用于工业控制网络中;而Modbus TCP作为基于以太网的通信协议,因其简单易…...
springboot3 WebClient
1 介绍 在 Spring 5 之前,如果我们想要调用其他系统提供的 HTTP 服务,通常可以使用 Spring 提供的 RestTemplate 来访问,不过由于 RestTemplate 是 Spring 3 中引入的同步阻塞式 HTTP 客户端,因此存在一定性能瓶颈。根据 Spring 官…...
牛客周赛 Round 83
A.和猫猫一起起舞! 思路:遇到‘U’和‘D’,输出‘R’或者‘L’;遇到‘R’和‘L’,输出‘U’或者‘D’.(这题比较简单) AC代码: void solve() {int n, m, k;char ch;cin >> ch;if (ch U || ch D)…...
硬通货用Deekseek做一个Vue.js组件开发的教程
安装 Node.js 与 Vue CLI npm install -g vue/cli vue create my-vue-project cd my-vue-project npm run serve 通过 Vue CLI 可快速生成项目骨架,默认配置适合新手快速上手 目录结构 src/ ├── components/ # 存放组件文件 │ └── …...
Windows权限维持之利用安全描述符隐藏服务后门进行权限维持(八)
我们先打开cs的服务端 然后我们打开客户端 我们点击连接 然后弹出这个界面 然后我们新建一个监听器 然后我们生成一个beacon 然后把这个复制到目标主机 然后我们双击 运行 然后cs这边就上线了 然后我们把进程结束掉 然后我们再把他删除掉 然后我们创建服务 将后门程序注册…...
Ubuntu20.04双系统安装及软件安装(七):Anaconda3
Ubuntu20.04双系统安装及软件安装(七):Anaconda3 打开Anaconda官网,在右侧处填写邮箱(要真实有效!),然后Submit。会出现如图示的Success界面。 进入填写的邮箱,有一封Ana…...
【极光 Orbit•STC8A-8H】02. STC8 单片机工程模板创建
【极光 Orbit•STC8A-8H】02. STC8 单片机工程模板创建 七绝单片机 小小芯片大乾坤, 集成世界在其中。 初学虽感千重难, 实践方知奥妙通。 今天的讲法和过去不同,直接来一个多文件模块化的工程模板创建,万事开头难,…...
Spring Boot WebFlux 中 WebSocket 生命周期解析
Spring Boot WebFlux 中的 WebSocket 提供了一种高效、异步的方式来处理客户端与服务器之间的双向通信。WebSocket 连接的生命周期包括连接建立、消息传输、连接关闭以及资源清理等过程。此外,为了确保 WebSocket 连接的稳定性和可靠性,我们可以加入重试…...
PostgreSQL中的事务隔离
1. 事务隔离的概念 在数据库管理系统中,事务隔离是一项重要的功能,它能确保在并发访问数据库时事务之间能够独立运行,不会相互干扰。数据库系统通常支持不同级别的事务隔离,用来满足不同应用程序之间的需求。 2. 事务隔离的种类…...
基于Rye的Django项目通过Pyinstaller用Github工作流简单打包
前言 Rye的介绍和安装 Ryehttps://rye.astral.sh/Rye 完整使用教程_安装rye-CSDN博客https://blog.csdn.net/zhenndbc/article/details/144544692 正文 项目建立 配置好环境后 新建文件夹 新建文件夹,进入项目 初始化 rye init下载依赖 rye syncpycharm 打…...
ubuntu 20.04 C++ 源码编译 cuda版本 opencv4.5.0
前提条件是安装好了cuda和cudnn 点击下载: opencv_contrib4.5.0 opencv 4.5.0 解压重命名后 进入opencv目录,创建build目录 “CUDA_ARCH_BIN ?” 这里要根据显卡查询一下,我的cuda是11,显卡1650,所以是7.5 查询链接:…...
【VUE】第一期——初使用、基本语法
目录 0 前言 1 准备工作 1.1 创建vue实例 1.2 vue开发者工具 2 插值表达式 2.1 基本用法 3 常用指令 3.1 内容渲染指令 3.1.1 v-text 3.1.2 v-html 3.2 条件渲染指令 3.2.1 v-show 3.2.2 v-if 3.2.3 v-else 和 v-else-if 3.3 事件绑定指令 3.3.1 内联语句 3.3…...
计算光学成像与光学计算概论
计算光学成像所涉及研究的内容非常广泛,虽然计算光学成像的研究内容是发散的,但目的都是一致的:如何让相机记录到客观实物更丰富的信息,延伸并扩展人眼的视觉感知。总的来说,计算光学成像现阶段已经取得了很多令人振奋…...
开启科创服务新篇章:八月瓜科技CRM数字化管理系统成功上线
近日,北京八月瓜科技有限公司(以下简称 “八月瓜科技”)与纷享销客达成深度战略合作,成功部署并上线CRM数字化管理系统。此次合作是八月瓜科技在数字化转型进程中的重要里程碑,标志着其在科技创新服务领域的数字化变革…...
AI提示词(Prompt)的理解和学习指南
AI提示词(Prompt)的理解和学习指南 一、什么是AI提示词? AI提示词(Prompt)是用户输入给人工智能模型的指令或问题,用于引导模型生成特定类型的回答或内容。它如同与AI沟通的“钥匙”,设计得当…...
记录一些面试遇到的问题
重载和重写的区别 重载是overload,覆盖是override 重载属于编译时多态,覆盖属于运行时多态 运行时多态和编译时多态 运行时多态指的是在运行的时候才知道要调用哪一个函数,编译时多态是指在编译的时候就知道调用哪一个函数。 运行时多态…...
OpenHarmony4.0_Linux环境搭建
查看链接:OpenHarmony4.0_Linux环境搭建https://www.yuque.com/xinzaigeek/jishu/fs9msruqhd5nhw4i...
练习(含atoi的模拟实现,自定义类型等练习)
一、结构体大小的计算及位段 (结构体大小计算及位段 详解请看:自定义类型:结构体进阶-CSDN博客) 1.在32位系统环境,编译选项为4字节对齐,那么sizeof(A)和sizeof(B)是多少? #pragma pack(4)st…...
自然语言处理——循环神经网络
自然语言处理——循环神经网络 循环神经网络应用到基于机器学习的自然语言处理任务序列到类别同步的序列到序列模式异步的序列到序列模式 参数学习和长程依赖问题基于门控的循环神经网络门控循环单元(GRU)长短期记忆神经网络(LSTM)…...
【开发技术】.Net使用FFmpeg视频特定帧上绘制内容
目录 一、目的 二、解决方案 2.1 什么是FFmpeg 2.2 FFmpeg主要功能 2.3 使用Xabe.FFmpeg调用FFmpeg功能 2.4 使用 FFmpeg 的 drawbox 滤镜来绘制 ROI 三、总结 一、目的 当前市场上有很多目标检测智能识别的相关算法,当前调用一个医疗行业的AI识别算法后返回…...
Web 架构之 CDN 加速原理与落地实践
文章目录 一、思维导图二、正文内容(一)CDN 基础概念1. 定义2. 组成部分 (二)CDN 加速原理1. 请求路由2. 内容缓存3. 内容更新 (三)CDN 落地实践1. 选择 CDN 服务商2. 配置 CDN3. 集成到 Web 架构 …...
rnn判断string中第一次出现a的下标
# coding:utf8 import torch import torch.nn as nn import numpy as np import random import json""" 基于pytorch的网络编写 实现一个RNN网络完成多分类任务 判断字符 a 第一次出现在字符串中的位置 """class TorchModel(nn.Module):def __in…...
React---day11
14.4 react-redux第三方库 提供connect、thunk之类的函数 以获取一个banner数据为例子 store: 我们在使用异步的时候理应是要使用中间件的,但是configureStore 已经自动集成了 redux-thunk,注意action里面要返回函数 import { configureS…...
技术栈RabbitMq的介绍和使用
目录 1. 什么是消息队列?2. 消息队列的优点3. RabbitMQ 消息队列概述4. RabbitMQ 安装5. Exchange 四种类型5.1 direct 精准匹配5.2 fanout 广播5.3 topic 正则匹配 6. RabbitMQ 队列模式6.1 简单队列模式6.2 工作队列模式6.3 发布/订阅模式6.4 路由模式6.5 主题模式…...
C# 表达式和运算符(求值顺序)
求值顺序 表达式可以由许多嵌套的子表达式构成。子表达式的求值顺序可以使表达式的最终值发生 变化。 例如,已知表达式3*52,依照子表达式的求值顺序,有两种可能的结果,如图9-3所示。 如果乘法先执行,结果是17。如果5…...
向量几何的二元性:叉乘模长与内积投影的深层联系
在数学与物理的空间世界中,向量运算构成了理解几何结构的基石。叉乘(外积)与点积(内积)作为向量代数的两大支柱,表面上呈现出截然不同的几何意义与代数形式,却在深层次上揭示了向量间相互作用的…...
echarts使用graphic强行给图增加一个边框(边框根据自己的图形大小设置)- 适用于无法使用dom的样式
pdf-lib https://blog.csdn.net/Shi_haoliu/article/details/148157624?spm1001.2014.3001.5501 为了完成在pdf中导出echarts图,如果边框加在dom上面,pdf-lib导出svg的时候并不会导出边框,所以只能在echarts图上面加边框 grid的边框是在图里…...










