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...

使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式
一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明:假设每台服务器已…...

测试微信模版消息推送
进入“开发接口管理”--“公众平台测试账号”,无需申请公众账号、可在测试账号中体验并测试微信公众平台所有高级接口。 获取access_token: 自定义模版消息: 关注测试号:扫二维码关注测试号。 发送模版消息: import requests da…...

iOS 26 携众系统重磅更新,但“苹果智能”仍与国行无缘
美国西海岸的夏天,再次被苹果点燃。一年一度的全球开发者大会 WWDC25 如期而至,这不仅是开发者的盛宴,更是全球数亿苹果用户翘首以盼的科技春晚。今年,苹果依旧为我们带来了全家桶式的系统更新,包括 iOS 26、iPadOS 26…...

python/java环境配置
环境变量放一起 python: 1.首先下载Python Python下载地址:Download Python | Python.org downloads ---windows -- 64 2.安装Python 下面两个,然后自定义,全选 可以把前4个选上 3.环境配置 1)搜高级系统设置 2…...

【大模型RAG】Docker 一键部署 Milvus 完整攻略
本文概要 Milvus 2.5 Stand-alone 版可通过 Docker 在几分钟内完成安装;只需暴露 19530(gRPC)与 9091(HTTP/WebUI)两个端口,即可让本地电脑通过 PyMilvus 或浏览器访问远程 Linux 服务器上的 Milvus。下面…...

cf2117E
原题链接:https://codeforces.com/contest/2117/problem/E 题目背景: 给定两个数组a,b,可以执行多次以下操作:选择 i (1 < i < n - 1),并设置 或,也可以在执行上述操作前执行一次删除任意 和 。求…...

现代密码学 | 椭圆曲线密码学—附py代码
Elliptic Curve Cryptography 椭圆曲线密码学(ECC)是一种基于有限域上椭圆曲线数学特性的公钥加密技术。其核心原理涉及椭圆曲线的代数性质、离散对数问题以及有限域上的运算。 椭圆曲线密码学是多种数字签名算法的基础,例如椭圆曲线数字签…...

select、poll、epoll 与 Reactor 模式
在高并发网络编程领域,高效处理大量连接和 I/O 事件是系统性能的关键。select、poll、epoll 作为 I/O 多路复用技术的代表,以及基于它们实现的 Reactor 模式,为开发者提供了强大的工具。本文将深入探讨这些技术的底层原理、优缺点。 一、I…...
【HarmonyOS 5 开发速记】如何获取用户信息(头像/昵称/手机号)
1.获取 authorizationCode: 2.利用 authorizationCode 获取 accessToken:文档中心 3.获取手机:文档中心 4.获取昵称头像:文档中心 首先创建 request 若要获取手机号,scope必填 phone,permissions 必填 …...

学习STC51单片机32(芯片为STC89C52RCRC)OLED显示屏2
每日一言 今天的每一份坚持,都是在为未来积攒底气。 案例:OLED显示一个A 这边观察到一个点,怎么雪花了就是都是乱七八糟的占满了屏幕。。 解释 : 如果代码里信号切换太快(比如 SDA 刚变,SCL 立刻变&#…...