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 configuration
        PUBLIC "-//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 mapper
        PUBLIC "-//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 mapper
        PUBLIC "-//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 o
                                              where 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 mapper
        PUBLIC "-//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 对象的具体信息

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

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

相关文章

在Linux中开发OpenGL——检查开发环境对OpenGL ES的支持

由于移动端GPU规模有限&#xff0c;厂商并没有实现完整的OpenGL特性&#xff0c;而是实现了它的子集——OpenGL ES。因此如果需要开发的程序要支持移动端平台&#xff0c;最好使用OpenGL ES开发。 1、 下载支持库、OpenGL ES Demo 1.1、下载PowerVRSDK支持库作为准备&#xff…

【Python项目】基于深度学习的电影评论情感分析系统

【Python项目】基于深度学习的电影评论情感分析系统 技术简介&#xff1a;采用Python技术、Flask框架、MySQL数据库、Word2Vec模型等实现。 系统简介&#xff1a;该系统基于深度学习技术&#xff0c;特别是Word2Vec模型&#xff0c;用于分析电影评论的情感倾向。系统分为前台…

SLAM评估工具安装及使用EVO(Ubuntu20.04安装evo)--缺少 onnx 库还有Pandas 版本不兼容解决

介绍一下我的是ubuntu20.04.机载电脑是orinnx&#xff0c;通过源码烧写的系统。 首先打开终端&#xff0c;输入 pip install evo --upgrade --no-binary evo 安装过程中出现如下问题 缺少 onnx 库还有Pandas 版本不兼容&#xff0c; ONNX&#xff08;Open Neural Network E…

Arcgis中添加脚本工具箱

文章目录 准备资料1、打开arcmap2、找到目录窗口3、复制粘贴工具箱的路径4、添加或者确认python脚本路径准备资料 (1)工具箱 (2)python脚本 1、打开arcmap 2、找到目录窗口 3、复制粘贴工具箱的路径 4、添加或者确认python脚本路径 脚本上右键属性(注意:脚本内容和路径…

第二次CCF-CSP认证(思路及源码)

第二次CCF-CSP认证 第一道&#xff08;easy&#xff09;思路及AC代码 第二道&#xff08;easy&#xff09;基本思路及AC代码 第三道&#xff08;mid&#xff09;基本思路及AC代码solution 1 (模拟)solution 2&#xff08;KMP&#xff09; 第一道&#xff08;easy&#xff09; 题…

RAGflow 无法加载Embedding模型

部署0.17版本的RAGflow&#xff0c;在模型列表中已经添加了嵌入模型&#xff0c;但是知识库配置时&#xff0c;嵌入模型灰显&#xff1a; 问题原因&#xff1a; 提前上传了一个文档&#xff0c;在知识库有文档之后&#xff0c;就不能够修改嵌入模型了。删除文档之后&#xff0…

C++ Primer 拷贝、赋值与销毁

欢迎阅读我的 【CPrimer】专栏 专栏简介&#xff1a;本专栏主要面向C初学者&#xff0c;解释C的一些基本概念和基础语言特性&#xff0c;涉及C标准库的用法&#xff0c;面向对象特性&#xff0c;泛型特性高级用法。通过使用标准库中定义的抽象设施&#xff0c;使你更加适应高级…

【够用就好006】如何从零开发游戏上架steam面向AI编程的godot独立游戏制作实录001流程

记录工作实践 这是全新的系列&#xff0c;一直有个游戏制作梦 感谢AI时代&#xff0c;让这一切变得可行 长欢迎共同见证&#xff0c;期更新&#xff0c;欢迎保持关注&#xff0c;待到游戏上架那一天&#xff0c;一起玩 面向AI编程的godot独立游戏制作流程实录001 本期是第…

计算机毕业设计Python+DeepSeek-R1大模型空气质量预测分析(源码+文档+PPT+讲解)

温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 作者简介&#xff1a;Java领…

【文生图】windows 部署stable-diffusion-webui

windows 部署stable-diffusion-webui AUTOMATIC1111 stable-diffusion-webui Detailed feature showcase with images: 带图片的详细功能展示: Original txt2img and img2img modes 原始的 txt2img 和 img2img 模式 One click install and run script (but you still must i…

单片机项目复刻需要的准备工作

一、前言 复刻单片机的项目的时候&#xff0c;有些模块是需要焊接的。很多同学对焊接没有概念。 这里说一下做项目的基本工具。 比如&#xff1a;像这种模块&#xff0c;都需要自己焊接了排针才可以链接的。 二、基本模块 2.1 单排排针 一些模块买回来是没有焊接的&#x…

微服务概览与治理

微服务概览与治理 1. 微服务架构的演进 1.1 引言 当我们讨论微服务时&#xff0c;我们并不是在谈论一种炫酷的新技术&#xff0c;而是在寻找一种更好的方式来组织我们的软件系统&#xff0c;使其更易扩展、更易维护。软件架构的发展历程往往是对业务需求和技术挑战的回应。从…

《代码随想录第五十七天》——孤岛的总面积、沉没孤岛、水流问题、建造最大岛屿

《代码随想录第五十七天》——孤岛的总面积、沉没孤岛、水流问题、建造最大岛屿 本篇文章的所有内容仅基于C撰写。 1. 孤岛的总面积 1.1 题目 孤岛的总面积 题目描述 给定一个由 1&#xff08;陆地&#xff09;和 0&#xff08;水&#xff09;组成的矩阵&#xff0c;岛屿指…

IntelliJ IDEA 华为云远程开发配置步骤

1.连接华为云主机,点击New Project 2.输入用户名与主机IP后连接 3.输入密码授权连接 4.继续连接 注意,远程主机内存最少要4G才能启动后端IDE 5.连接华为云主机成功,下载IDE并连接 选择项目位置

23种设计模式之单例模式(Singleton Pattern)【设计模式】

文章目录 一、简介二、关键点三、实现单例模式的步骤四、C#示例4.1 简单的单例模式4.2 线程安全的单例模式&#xff08;双重检查锁定&#xff09;4.3 静态初始化单例模式 五、单例模式优缺点5.1 优点5.2 缺点 六、适用场景七、示例的现实应用 一、简介 单例模式&#xff08;Si…

c盘爆红后,使用diskgenius给C盘无损扩容,操作记录

diskgenius下载链接 参考链接 操作前环境 之前电脑配置了一个每天定时清理c盘临时文件的脚本&#xff0c;依然阻止不了c盘爆红。 实测DISKGENIUS 无损扩容有效&#xff0c;扩容前的环境&#xff1a; 扩容前&#xff0c;C区可用空间 9G,爆红C盘D盘都是 NTFS 格式&#xff0c;D…

【音视频】ffplay简单过滤器

一、ffplay简单过滤器 视频旋转&#xff1a;借助transpose滤镜 ffplay -i 1.mp4 -vf transpose1这里选择不同的数字是不同的方向&#xff1a; 视频翻转&#xff1a;借助hflip/vflip实现水平和垂直翻转&#xff1a; 水平翻转 ffplay 1.mp4 -vf hflip垂直翻转 ffplay 1.mp4 …

蓝桥杯备考:动态规划路径类dp之迷雾森林

step1 :确定状态表示 f[i][j]表示 n,n 到 i,j的方案数 step2 : 推导状态转移方程初始化 step3 确认填表顺序 应该是从下往上&#xff0c;从左往右 step4:答案在f[1][m] 代码实现&#xff1a; #include <iostream> #include <cstring> using namespace std; i…

零售交易流程相关知识(top-down拆解)

引入 关于POS机交易时的后台数据交互 模块之间数据交换&#xff0c;都可以能被窃取或篡改。由此引入加密、解密机制和签名、验签机制 经典的加密、解密机制&#xff1a; 对称加密&#xff1a;DES\ TDES\ AES\ RC4 非对称加密&#xff1a;RSA\ DSA\ ECC 经典的签名、验签…

threejs:用着色器给模型添加光带扫描效果

第一步&#xff1a;给模型添加光带 首先创建一个立方体&#xff0c;不进行任何缩放平移操作&#xff0c;也不要set position。 基础代码如下&#xff1a; 在顶点着色器代码里varying vec3 vPosition;vPosition position;获得threejs自动计算的顶点坐标插值&#xff08;也就…