当前位置: 首页 > news >正文

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 的关联映射(一对一,一对多,多对多)

前言 在前面我们已经了解了&#xff0c;mybatis 的基本用法&#xff0c;动态SQL&#xff0c;学会使用mybatis 来操作数据库。但这些主要操作还是针对 单表实现的。在实际的开发中&#xff0c;对数据库的操作&#xff0c;常常涉及多张表。 因此本篇博客的目标&#xff1a;通过my…...

深度解码!清华大学第六弹《AIGC发展研究3.0版》

在Grok3与GPT-4.5相继发布之际&#xff0c;《AIGC发展研究3.0版》的重磅报告——这份长达200页的行业圣经&#xff0c;不仅预测了2025年AI技术爆发点&#xff0c;更将「天人合一」的东方智慧融入AI伦理建构&#xff0c;堪称数字时代的《道德经》。 文档&#xff1a;清华大学第…...

/dev/console文件详解

/dev/console概览 /dev/console 是 Linux 系统中的一个特殊设备文件&#xff0c;通常用于与系统的控制台进行交互。它的作用和特点如下&#xff1a; 1. 作用 init 进程&#xff08;PID 1&#xff09;和某些系统服务在启动时会使用 /dev/console 进行日志输出&#xff0c;以确…...

ProfibusDP主站转ModbusTCP网关如何进行数据互换

ProfibusDP主站转ModbusTCP网关如何进行数据互换 在现代工业自动化领域&#xff0c;通信协议的多样性和复杂性不断增加。Profibus DP作为一种经典的现场总线标准&#xff0c;广泛应用于工业控制网络中&#xff1b;而Modbus TCP作为基于以太网的通信协议&#xff0c;因其简单易…...

springboot3 WebClient

1 介绍 在 Spring 5 之前&#xff0c;如果我们想要调用其他系统提供的 HTTP 服务&#xff0c;通常可以使用 Spring 提供的 RestTemplate 来访问&#xff0c;不过由于 RestTemplate 是 Spring 3 中引入的同步阻塞式 HTTP 客户端&#xff0c;因此存在一定性能瓶颈。根据 Spring 官…...

牛客周赛 Round 83

A.和猫猫一起起舞&#xff01; 思路&#xff1a;遇到‘U’和‘D’&#xff0c;输出‘R’或者‘L’&#xff1b;遇到‘R’和‘L’&#xff0c;输出‘U’或者‘D’.(这题比较简单) AC代码&#xff1a; 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 可快速生成项目骨架&#xff0c;默认配置适合新手快速上手 目录结构‌ src/ ├── components/ # 存放组件文件 │ └── …...

Windows权限维持之利用安全描述符隐藏服务后门进行权限维持(八)

我们先打开cs的服务端 然后我们打开客户端 我们点击连接 然后弹出这个界面 然后我们新建一个监听器 然后我们生成一个beacon 然后把这个复制到目标主机 然后我们双击 运行 然后cs这边就上线了 然后我们把进程结束掉 然后我们再把他删除掉 然后我们创建服务 将后门程序注册…...

Ubuntu20.04双系统安装及软件安装(七):Anaconda3

Ubuntu20.04双系统安装及软件安装&#xff08;七&#xff09;&#xff1a;Anaconda3 打开Anaconda官网&#xff0c;在右侧处填写邮箱&#xff08;要真实有效&#xff01;&#xff09;&#xff0c;然后Submit。会出现如图示的Success界面。 进入填写的邮箱&#xff0c;有一封Ana…...

【极光 Orbit•STC8A-8H】02. STC8 单片机工程模板创建

【极光 Orbit•STC8A-8H】02. STC8 单片机工程模板创建 七绝单片机 小小芯片大乾坤&#xff0c; 集成世界在其中。 初学虽感千重难&#xff0c; 实践方知奥妙通。 今天的讲法和过去不同&#xff0c;直接来一个多文件模块化的工程模板创建&#xff0c;万事开头难&#xff0c;…...

Spring Boot WebFlux 中 WebSocket 生命周期解析

Spring Boot WebFlux 中的 WebSocket 提供了一种高效、异步的方式来处理客户端与服务器之间的双向通信。WebSocket 连接的生命周期包括连接建立、消息传输、连接关闭以及资源清理等过程。此外&#xff0c;为了确保 WebSocket 连接的稳定性和可靠性&#xff0c;我们可以加入重试…...

PostgreSQL中的事务隔离

1. 事务隔离的概念 在数据库管理系统中&#xff0c;事务隔离是一项重要的功能&#xff0c;它能确保在并发访问数据库时事务之间能够独立运行&#xff0c;不会相互干扰。数据库系统通常支持不同级别的事务隔离&#xff0c;用来满足不同应用程序之间的需求。 2. 事务隔离的种类…...

基于Rye的Django项目通过Pyinstaller用Github工作流简单打包

前言 Rye的介绍和安装 Ryehttps://rye.astral.sh/Rye 完整使用教程_安装rye-CSDN博客https://blog.csdn.net/zhenndbc/article/details/144544692 正文 项目建立 配置好环境后 新建文件夹 新建文件夹&#xff0c;进入项目 初始化 rye init下载依赖 rye syncpycharm 打…...

ubuntu 20.04 C++ 源码编译 cuda版本 opencv4.5.0

前提条件是安装好了cuda和cudnn 点击下载&#xff1a; opencv_contrib4.5.0 opencv 4.5.0 解压重命名后 进入opencv目录&#xff0c;创建build目录 “CUDA_ARCH_BIN ?” 这里要根据显卡查询一下,我的cuda是11&#xff0c;显卡1650&#xff0c;所以是7.5 查询链接&#xff1a;…...

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

计算光学成像与光学计算概论

计算光学成像所涉及研究的内容非常广泛&#xff0c;虽然计算光学成像的研究内容是发散的&#xff0c;但目的都是一致的&#xff1a;如何让相机记录到客观实物更丰富的信息&#xff0c;延伸并扩展人眼的视觉感知。总的来说&#xff0c;计算光学成像现阶段已经取得了很多令人振奋…...

开启科创服务新篇章:八月瓜科技CRM数字化管理系统成功上线

近日&#xff0c;北京八月瓜科技有限公司&#xff08;以下简称 “八月瓜科技”&#xff09;与纷享销客达成深度战略合作&#xff0c;成功部署并上线CRM数字化管理系统。此次合作是八月瓜科技在数字化转型进程中的重要里程碑&#xff0c;标志着其在科技创新服务领域的数字化变革…...

AI提示词(Prompt)的理解和学习指南

AI提示词&#xff08;Prompt&#xff09;的理解和学习指南 一、什么是AI提示词&#xff1f; AI提示词&#xff08;Prompt&#xff09;是用户输入给人工智能模型的指令或问题&#xff0c;用于引导模型生成特定类型的回答或内容。它如同与AI沟通的“钥匙”&#xff0c;设计得当…...

记录一些面试遇到的问题

重载和重写的区别 重载是overload&#xff0c;覆盖是override 重载属于编译时多态&#xff0c;覆盖属于运行时多态 运行时多态和编译时多态 运行时多态指的是在运行的时候才知道要调用哪一个函数&#xff0c;编译时多态是指在编译的时候就知道调用哪一个函数。 运行时多态…...

OpenHarmony4.0_Linux环境搭建

查看链接&#xff1a;OpenHarmony4.0_Linux环境搭建https://www.yuque.com/xinzaigeek/jishu/fs9msruqhd5nhw4i...

DeepSeek开源Day5:3FSsmallpond技术详解

2 月 24 日&#xff0c;DeepSeek 启动 “开源周”&#xff0c;第四个开源的代码库为 3FS&smallpond&#xff08;又是一下发布了两个&#xff09;。 3FS&#xff08;Fire-Flyer File System&#xff09;是 DeepSeek 内部开发的一款高性能分布式文件系统&#xff0c;旨在为 A…...

Java集合面试篇

目录 1.概念 1.1.数组与集合的区别&#xff0c;用过哪些&#xff1f; 1.2.说说Java中的集合&#xff1f; 1.3.Java中的线程安全的集合是什么&#xff1f; 1.4.集合遍历的方法有哪些&#xff1f; 2.List 2.1.list可以一边遍历一边修改元素吗&#xff1f; 2.2.Arraylist和…...

plt和cv2有不同的图像表示方式和颜色通道顺序

在处理图像时&#xff0c;matplotlib.pyplot (简称 plt) 和 OpenCV (简称 cv2) 有不同的图像表示方式和颜色通道顺序。了解这些区别对于正确处理和显示图像非常重要。 1. 图像形状和颜色通道顺序 matplotlib.pyplot (plt) 形状&#xff1a;plt 通常使用 (height, width, cha…...

Sqlserver安全篇之_手工创建TLS用到的pfx证书文件

Sqlserver官方提供的Windows Powershell脚本 https://learn.microsoft.com/zh-cn/sql/database-engine/configure-windows/configure-sql-server-encryption?viewsql-server-ver16 # Define parameters $certificateParams {Type "SSLServerAuthentication"Subje…...

基于RapidOCR与DeepSeek的智能表格转换技术实践

基于RapidOCR与DeepSeek的智能表格转换技术实践 一、技术背景与需求场景 在金融分析、数据报表处理等领域&#xff0c;存在大量图片格式的表格数据需要结构化处理。本文介绍基于开源RapidOCR表格识别与DeepSeek大模型的智能转换方案&#xff0c;实现以下典型场景&#xff1a; …...

创建阿里云CDN

创建阿里云CDN CDN域名管理 SSL证书上传...

tomcat的web管理

进入到conf cd /usr/local/tomcat/conf/备份tomcat-users.xml cp tomcat-users.xml{.,bak}编辑tomcat-users.xml vim tomcat-users.xml增加以下内容 配置tomcat-users.xml <role rolename"manager-gui"/><role rolename"admin-gui"/><use…...

【Linux系统】-----进程初相识:原理与概念全解析

Linux系列 文章目录 Linux系列前言一、进程的概念二、进程的管理三、Linux操作系统的进程管理3.1、进程标识符3.2、查看进程3.3、查看进程的PID和PPID 前言 经过前两篇文章的铺垫&#xff0c;我们对操作系统的管理方式已经有了比较完整的认识&#xff0c;今天我们将学习Linux比…...

分布式系统设计(架构能力)

一、微服务架构 服务治理 Nacos 注册中心&#xff08;AP模式&#xff09; CAP选择&#xff1a;Nacos 默认采用 AP 模式&#xff08;可用性 分区容忍性&#xff09;&#xff0c;通过心跳检测实现服务健康管理。服务发现&#xff1a;客户端定时拉取服务列表&#xff0c;支持权重…...

171. Excel 表列序号

Excel 表列序号 题目描述尝试做法推荐做法 题目描述 给你一个字符串 columnTitle &#xff0c;表示 Excel 表格中的列名称。返回 该列名称对应的列序号 。 例如&#xff1a; A -> 1 B -> 2 C -> 3 … Z -> 26 AA -> 27 AB -> 28 … 示例 1: 输入: colum…...