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

MyBatis系统学习(四)——MyBatis的关联映射和缓存机制

MyBatis 是一个优秀的持久层框架,它通过 XML 或注解将 Java 对象与 SQL 语句相映射,简化了 JDBC 代码,增强了 SQL 的灵活性。在复杂业务场景中,数据库表之间经常存在一对一、一对多、多对多的关联关系,MyBatis 提供了相应的机制来处理这些映射问题。此外,MyBatis 的缓存机制可以有效提高数据访问效率。

接下来,我将详细介绍 MyBatis 中的关联映射和缓存机制。

一、MyBatis 关联映射概述

在关系型数据库中,表与表之间的关联关系常见的有:

  • 一对一(One-to-One):两个表中一条记录对应另一个表中的一条记录。
  • 一对多(One-to-Many):一个表中一条记录对应另一个表中的多条记录。
  • 多对多(Many-to-Many):两个表中的多条记录彼此关联。

MyBatis 提供了以下两种主要方式来实现关联映射:

  1. 使用 resultMap 标签进行复杂的对象关系映射
  2. 通过注解来实现简单的映射

二、一对一查询

一对一关系通常体现在数据库中表与表之间通过外键关联。MyBatis 支持通过 resultMap 标签来定义一对一的关联关系。

实现步骤:

  1. 在数据库中,两个表具有外键关联。例如,User 表和 Address 表,User 表有一个 address_id 外键指向 Address 表。
  2. 在 MyBatis 的配置文件中,通过 resultMap 定义关联关系。
示例:

假设我们有 UserAddress 表,User 表中有一个 address_id 作为外键关联 Address 表。

<!-- 一对一映射 resultMap -->
<resultMap id="userResultMap" type="com.example.User"><id property="id" column="id"/><result property="name" column="name"/><association property="address" javaType="com.example.Address"><id property="id" column="address_id"/><result property="city" column="city"/><result property="street" column="street"/></association>
</resultMap><select id="selectUserWithAddress" resultMap="userResultMap">SELECT u.id, u.name, a.id AS address_id, a.city, a.streetFROM User uLEFT JOIN Address a ON u.address_id = a.idWHERE u.id = #{id}
</select>

这里,<association> 用于描述一对一的关系。User 对象的 address 属性将与 Address 对象对应。

三、一对多查询

一对多关系通常表示一个表中的一条记录可以对应另一个表中的多条记录。MyBatis 可以通过 collection 标签来处理一对多的关系。

示例:

假设 User 表和 Order 表存在一对多的关系,一个用户可以有多个订单。

<!-- 一对多映射 resultMap -->
<resultMap id="userWithOrdersResultMap" type="com.example.User"><id property="id" column="id"/><result property="name" column="name"/><collection property="orders" ofType="com.example.Order"><id property="id" column="order_id"/><result property="orderNumber" column="order_number"/><result property="amount" column="amount"/></collection>
</resultMap><select id="selectUserWithOrders" resultMap="userWithOrdersResultMap">SELECT u.id, u.name, o.id AS order_id, o.order_number, o.amountFROM User uLEFT JOIN Orders o ON u.id = o.user_idWHERE u.id = #{id}
</select>

这里使用 <collection> 标签定义了 User 对象中包含的 orders 集合。通过这个映射,MyBatis 会自动将查询到的 Order 记录映射到 User 对象的 orders 属性中。

四、多对多查询

多对多的关系通常通过中间表来表示,MyBatis 也可以处理这样的复杂关联。

示例:

假设 Student 表和 Course 表通过 Student_Course 中间表存在多对多关系。

<!-- 多对多映射 resultMap -->
<resultMap id="studentWithCoursesResultMap" type="com.example.Student"><id property="id" column="id"/><result property="name" column="name"/><collection property="courses" ofType="com.example.Course"><id property="id" column="course_id"/><result property="courseName" column="course_name"/></collection>
</resultMap><select id="selectStudentWithCourses" resultMap="studentWithCoursesResultMap">SELECT s.id, s.name, c.id AS course_id, c.course_nameFROM Student sLEFT JOIN Student_Course sc ON s.id = sc.student_idLEFT JOIN Course c ON sc.course_id = c.idWHERE s.id = #{id}
</select>

这里使用 <collection> 定义了 Student 对象中包含的 courses 集合。查询结果会自动映射到 Student 对象的 courses 属性中。

五、MyBatis 缓存机制

MyBatis 提供了两级缓存机制:

  1. 一级缓存(Local Cache):基于 SqlSession 的缓存。一级缓存默认开启,且作用范围是 SqlSession 级别的。在同一个 SqlSession 中执行相同的 SQL 语句,MyBatis 会从缓存中取数据而不是再去查询数据库。
  2. 二级缓存(Global Cache):基于 mapper 映射文件的缓存。作用范围是 mapper 映射文件级别,即同一个 mapper 中的多个 SqlSession 都可以共享该缓存。二级缓存需要手动配置开启。
一级缓存:
  • 默认情况下一级缓存是开启的。
  • 一级缓存的生效条件:同一个 SqlSession、相同的查询条件。
示例:
SqlSession session = sqlSessionFactory.openSession();
User user1 = session.selectOne("selectUser", 1); // 从数据库查询
User user2 = session.selectOne("selectUser", 1); // 从缓存中查询
二级缓存:

二级缓存需要在 mapper 映射文件中手动开启,且 Java 类必须实现序列化接口。

配置方式:
  1. 在 MyBatis 配置文件中开启二级缓存:

    <settings><setting name="cacheEnabled" value="true"/>
    </settings>
    
  2. mapper 文件中开启二级缓存:

    <cache/>
    
  3. Java 对象必须实现 Serializable 接口,确保对象能被序列化并存入缓存。

二级缓存失效的条件:
  • 执行了增删改操作,相关缓存会失效。
  • 不同的 SqlSession

六、MyBatis 相关常用知识点总结

  1. 动态 SQL:MyBatis 提供了 ifchoosewhenforeach 等标签来处理动态 SQL,满足多变的业务需求。
  2. resultMap 的使用resultMap 是 MyBatis 最强大的功能之一,它允许灵活地将查询结果映射到复杂的 Java 对象中。
  3. 多数据源支持:MyBatis 支持多数据源的配置,可以方便地在项目中切换或同时操作多个数据库。
  4. 分页插件:MyBatis 本身不提供分页功能,但是可以通过插件(如 PageHelper)来实现数据库层面的分页操作。

七、综合案例

假设我们有三个表:User 表、Order 表和 Product 表。User 表与 Order 表是一对多的关系,Order 表与 Product 表是多对多的关系(通过 Order_Product 中间表实现)。我们希望查询用户、用户的订单以及每个订单中的产品信息。

数据库表设计:
  • User 表:idname
  • Order 表:idorder_numberuser_id
  • Product 表:idproduct_name
  • Order_Product 表:order_idproduct_id
MyBatis 配置文件:
<!-- 综合案例 resultMap -->
<resultMap id="userWithOrdersAndProductsResultMap" type="com.example.User"><id property="id" column="id"/><result property="name" column="name"/><collection property="orders" ofType="com.example.Order"><id property="id" column="order_id"/><result property="orderNumber" column="order_number"/><collection property="products" ofType="com.example.Product"><id property="id" column="product_id"/><result property="productName" column="product_name"/></collection></collection>
</resultMap><select id="selectUserWithOrdersAndProducts" resultMap="userWithOrdersAndProductsResultMap">SELECT u.id, u.name, o.id AS order_id, o.order_number, p.id AS product_id, p.product_nameFROM User uLEFT JOIN Orders o ON u.id = o.user_idLEFT JOIN Order_Product op ON o.id = op.order_idLEFT JOIN Product p ON op.product_id = p.idWHERE u.id = #{id}
</select>
Java 类设计:
public class User implements Serializable {private Integer id;private String name;private List<Order> orders;// getters and setters
}public class Order implements Serializable {private Integer id;private String orderNumber;private List<Product> products;// getters and setters
}public class Product implements Serializable {private Integer id;private String productName;// getters and setters
}

通过以上配置和映射,当执行 selectUserWithOrdersAndProducts 查询时,MyBatis 会将用户、订单和订单中的产品信息自动映射到 User 对象及其关联的 OrderProduct 对象中。

结语

MyBatis 在处理复杂的对象关系映射时提供了极大的灵活性。通过 resultMap 和缓存机制,我们能够有效地管理查询结果并提升系统性能。在实际开发中,掌握 MyBatis 的这些功能,可以更轻松地应对持久层的复杂逻辑。

相关文章:

MyBatis系统学习(四)——MyBatis的关联映射和缓存机制

MyBatis 是一个优秀的持久层框架&#xff0c;它通过 XML 或注解将 Java 对象与 SQL 语句相映射&#xff0c;简化了 JDBC 代码&#xff0c;增强了 SQL 的灵活性。在复杂业务场景中&#xff0c;数据库表之间经常存在一对一、一对多、多对多的关联关系&#xff0c;MyBatis 提供了相…...

【iOS】present和push

【iOS】present和push present和push的比较 present和push都用于iOS的视图切换&#xff0c;并且切换都是可逆的&#xff0c;原始视图不会被销毁&#xff0c;还可以直接更改window的rootViewController来切换视图&#xff0c;但是这种方法不可逆&#xff0c;并且原始视图会被销毁…...

Axure RP 9最新安装程序及汉化包下载(支持Win、Mac版,附下载安装教程)

数月前Axure RP官方已经发布了Axure RP 9的消息&#xff0c;并计划在今年夏天发布beta版本。新版Axure RP 9将是该工具向前迈出的重要一步&#xff0c;其中包括一系列广泛的改进&#xff1a;全面的UI修改&#xff0c;新的设计和文档功能以及前所未有的内部优化。我们已经彻底重…...

k8s环境搭建(续)

查看节点信息并做快照 kubectl get nodes 将components.yml文件上传到master主机 创建nginx&#xff0c;会在添加一个新的pod kubectl run nginx --imagesnginx:latest 查看nginx的pod信息 [rootk8s-master ~]# kubectl get po -Aowide|grep nginx 出现错误&#xff0c;查…...

kali——binwalk的使用

目录 前言 使用方法 分析文件 分离文件 前言 binwalk是一个用于分析、逆向工程和提取固件映像的工具。 binwalk能够分析固件映像文件&#xff0c;识别其中包含的文件。例如&#xff0c;它可以从一个设备固件中提取出压缩文件或图片等嵌入内容。 使用方法 分析文件 binwa…...

Ubuntu 24.04中安装virtualenv

在Ubuntu 24.04中安装virtualenv&#xff0c;可以按照以下步骤进行&#xff1a; 1. 确保Python已安装‌&#xff1a; 在终端中输入python --version或python3 --version来检查Python的安装情况。 python3 --version2. 安装pip‌&#xff08;如果尚未安装&#xff09;&#x…...

一个简约的uniapp登录界面,基于uniapp+vue3+uview-plus

uniapp-vue3-template 一个简约的uniapp登录界面&#xff0c;基于uniappvue3uview-plus 页面主要包括&#xff1a;用户登录&#xff0c;手机验证码登录&#xff0c;用户注册&#xff0c;重置密码等页面 登录进去后为空白模板 源码在文末 界面 源码 uniapp登录界面源码...

系统架构设计师 需求分析篇二

&#x1f4d8; 面向对象分析方法 1. 用例模型 &#x1f4c8; 构建用例模型一般需要经历 4 个阶段&#xff1a; 识别参与者 &#x1f50d;&#xff1a;识别与系统交互的所有事物。合并需求获得用例 &#x1f517;&#xff1a;将需求分配给予其相关的参与者。细化用例描述 &am…...

IP 协议分析《实验报告》

目录 一、 实验目的 二、实验设备和环境 三、实验记录 1、实验环境搭建 2、IP 协议分析 1.设置抓包接口 2.IP 报文分析 3.报文长度计算 4.生存时间 TTL 5.分析总结 3、IP分片 1.IP 分片简介 2.捕获分组 3.结果分析 一、 实验目的 1、掌握 IP 协议数据报格式&…...

人工智能开发实战matplotlib库应用基础

内容导读 matplotlib简介绘制直方图绘制撒点图 一、matplotlib简介 matplotlib是一个Python 2D绘图库&#xff0c;它以多种硬拷贝格式和跨平台的交互式环境生成高质量的图形。 matplotlib 尝试使容易的事情变得更容易&#xff0c;使困难的事情变得可能。 我们只需几行代码…...

Android 源码集成可卸载 APP

android系统包含三类APP: 1、可自由卸载APP安装在 /data/app目录下。 2、系统APP放在 /system/app目录。 3、特权APP放在 /system/priv-app目录。 系统编译后&#xff0c;打包前&#xff0c; /data分区不起作用&#xff0c;因此系统打包前&#xff0c;可以先将APP全部拷贝到 /…...

cJSON-轻量级解析模块、字符串的神——编织STM32C8T6与阿里云信息传递的纽带

编写方向&#xff1a;本人就不泛泛的编写一篇什么一文学会cJSON了&#xff0c;没什么突出点&#xff0c;也就我水水字数&#xff0c;你们看来看去也不懂&#xff0c;本人是从上阿里云传信息接触的cJSON的&#xff0c;我就此写一篇针对性的文章&#xff0c;希望对大家有用&#…...

【Git】Clone

当git clone失败时&#xff0c;出现 RPC failed; curl 92 HTTP/2 stream 0 was not closed cleanly: CANCEL (err 8) 错误&#xff0c;可能由于网络连接不稳定或仓库太大导致的。 可以尝试以下几种方法来解决这个问题&#xff1a; 增加 Git 的缓冲区大小&#xff1a; git confi…...

web开发 之 HTML、CSS、JavaScript、以及JavaScript的高级框架Vue(学习版2)

一、前言 接下来就是来解决这些问题 二、 Ajax 1.ajax javscript是网页三剑客之一&#xff0c;空用来控制网页的行为的 xml是一种标记语言&#xff0c;是用来存储数据的 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-…...

【课程学习】信号检测与估计II

b站 文章目录 1-概述 1-概述 线性、正交、平稳、高斯 研究线性模型&#xff0c;采用正交化方法&#xff0c;假设信号平稳&#xff0c;考虑信号的统计特性是高斯的。 本学期考虑&#xff0c;非线性、非正交、非平稳、非高斯。 阵列处理 1980-1990 MUSIC 稀疏性 2006-2012 LASS 时…...

【深度学习|PyTorch】基于 PyTorch 搭建 U-Net 深度学习语义分割模型——附代码及其解释!

【深度学习|PyTorch】基于 PyTorch 搭建 U-Net 深度学习语义分割模型——附代码及其解释&#xff01; 【深度学习|PyTorch】基于 PyTorch 搭建 U-Net 深度学习语义分割模型——附代码及其解释&#xff01; 论文地址&#xff1a; https://arxiv.org/abs/1505.04597 代码地址&a…...

DPDK基础入门(十):虚拟化

I/O虚拟化 全虚拟化&#xff1a;宿主机截获客户机对I/O设备的访问请求&#xff0c;然后通过软件模拟真实的硬件。这种方式对客户机而言非常透明&#xff0c;无需考虑底层硬件的情况&#xff0c;不需要修改操作系统。 半虚拟化&#xff1a;通过前端驱动/后端驱动模拟实现I/O虚拟…...

OpenCV_图像旋转超详细讲解

图像转置 transpose(src, dst); transpose()可以实现像素下标的x和y轴坐标进行对调&#xff1a;dst(i,j)src(j,i)&#xff0c;接口形式 transpose(InputArray src, // 输入图像OutputArray dst, // 输出 ) 图像翻转 flip(src, dst, 1); flip()函数可以实现对图像的水平翻转…...

关于 OceanBase 4.x 中被truncate的 table 不再支持进回收站的原因

近期&#xff0c;OceanBase的问答社区中收到了不少用户的询问&#xff0c;关于OceanBase 3.x版本支持被truncate的table进入回收站的功能&#xff0c;为何在升级到4.x版本后不再支持了&#xff1f;为了解答大家的疑惑&#xff0c;我们将通过这篇文章来浅析 OceanBase在4.x版本中…...

Numpy索引详解(数值索引,列表索引,布尔索引)

数值索引 数值索引类似列表索引操作使用[]&#xff0c;参数为下标&#xff0c;[0,len-1),高维数组的索引使用多个[]连用分别代表一维索引&#xff0c;二维索引... import numpy as np import torchnp.random.seed(1) data1 np.arange(5) data2 np.arange(15).reshape(3,5) …...

三维GIS开发cesium智慧地铁教程(5)Cesium相机控制

一、环境搭建 <script src"../cesium1.99/Build/Cesium/Cesium.js"></script> <link rel"stylesheet" href"../cesium1.99/Build/Cesium/Widgets/widgets.css"> 关键配置点&#xff1a; 路径验证&#xff1a;确保相对路径.…...

【JVM】- 内存结构

引言 JVM&#xff1a;Java Virtual Machine 定义&#xff1a;Java虚拟机&#xff0c;Java二进制字节码的运行环境好处&#xff1a; 一次编写&#xff0c;到处运行自动内存管理&#xff0c;垃圾回收的功能数组下标越界检查&#xff08;会抛异常&#xff0c;不会覆盖到其他代码…...

unix/linux,sudo,其发展历程详细时间线、由来、历史背景

sudo 的诞生和演化,本身就是一部 Unix/Linux 系统管理哲学变迁的微缩史。来,让我们拨开时间的迷雾,一同探寻 sudo 那波澜壮阔(也颇为实用主义)的发展历程。 历史背景:su的时代与困境 ( 20 世纪 70 年代 - 80 年代初) 在 sudo 出现之前,Unix 系统管理员和需要特权操作的…...

《C++ 模板》

目录 函数模板 类模板 非类型模板参数 模板特化 函数模板特化 类模板的特化 模板&#xff0c;就像一个模具&#xff0c;里面可以将不同类型的材料做成一个形状&#xff0c;其分为函数模板和类模板。 函数模板 函数模板可以简化函数重载的代码。格式&#xff1a;templa…...

【Redis】笔记|第8节|大厂高并发缓存架构实战与优化

缓存架构 代码结构 代码详情 功能点&#xff1a; 多级缓存&#xff0c;先查本地缓存&#xff0c;再查Redis&#xff0c;最后才查数据库热点数据重建逻辑使用分布式锁&#xff0c;二次查询更新缓存采用读写锁提升性能采用Redis的发布订阅机制通知所有实例更新本地缓存适用读多…...

Ubuntu Cursor升级成v1.0

0. 当前版本低 使用当前 Cursor v0.50时 GitHub Copilot Chat 打不开&#xff0c;快捷键也不好用&#xff0c;当看到 Cursor 升级后&#xff0c;还是蛮高兴的 1. 下载 Cursor 下载地址&#xff1a;https://www.cursor.com/cn/downloads 点击下载 Linux (x64) &#xff0c;…...

GraphQL 实战篇:Apollo Client 配置与缓存

GraphQL 实战篇&#xff1a;Apollo Client 配置与缓存 上一篇&#xff1a;GraphQL 入门篇&#xff1a;基础查询语法 依旧和上一篇的笔记一样&#xff0c;主实操&#xff0c;没啥过多的细节讲解&#xff0c;代码具体在&#xff1a; https://github.com/GoldenaArcher/graphql…...

从零开始了解数据采集(二十八)——制造业数字孪生

近年来&#xff0c;我国的工业领域正经历一场前所未有的数字化变革&#xff0c;从“双碳目标”到工业互联网平台的推广&#xff0c;国家政策和市场需求共同推动了制造业的升级。在这场变革中&#xff0c;数字孪生技术成为备受关注的关键工具&#xff0c;它不仅让企业“看见”设…...

基于stm32F10x 系列微控制器的智能电子琴(附完整项目源码、详细接线及讲解视频)

注&#xff1a;文章末尾网盘链接中自取成品使用演示视频、项目源码、项目文档 所用硬件&#xff1a;STM32F103C8T6、无源蜂鸣器、44矩阵键盘、flash存储模块、OLED显示屏、RGB三色灯、面包板、杜邦线、usb转ttl串口 stm32f103c8t6 面包板 …...

Win系统权限提升篇UAC绕过DLL劫持未引号路径可控服务全检项目

应用场景&#xff1a; 1、常规某个机器被钓鱼后门攻击后&#xff0c;我们需要做更高权限操作或权限维持等。 2、内网域中某个机器被钓鱼后门攻击后&#xff0c;我们需要对后续内网域做安全测试。 #Win10&11-BypassUAC自动提权-MSF&UACME 为了远程执行目标的exe或者b…...