MyBatis多表映射

news2024/11/30 6:38:03

1. 多表映射概念

MyBatis 思想是:数据库不可能永远是你所想或所需的那个样子。 我们希望每个数据库都具备良好的第三范式或 BCNF 范式,可惜它们并不都是那样。 如果能有一种数据库映射模式,完美适配所有的应用程序查询需求,那就太好了,而 ResultMap 就是 MyBatis 就是完美答案。
官方例子:我们如何映射下面这个语句?

<!-- 非常复杂的语句 -->
<select id="selectBlogDetails" resultMap="detailedBlogResultMap">
  select
       B.id as blog_id,
       B.title as blog_title,
       B.author_id as blog_author_id,
       A.id as author_id,
       A.username as author_username,
       A.password as author_password,
       A.email as author_email,
       A.bio as author_bio,
       A.favourite_section as author_favourite_section,
       P.id as post_id,
       P.blog_id as post_blog_id,
       P.author_id as post_author_id,
       P.created_on as post_created_on,
       P.section as post_section,
       P.subject as post_subject,
       P.draft as draft,
       P.body as post_body,
       C.id as comment_id,
       C.post_id as comment_post_id,
       C.name as comment_name,
       C.comment as comment_text,
       T.id as tag_id,
       T.name as tag_name
  from Blog B
       left outer join Author A on B.author_id = A.id
       left outer join Post P on B.id = P.blog_id
       left outer join Comment C on P.id = C.post_id
       left outer join Post_Tag PT on PT.post_id = P.id
       left outer join Tag T on PT.tag_id = T.id
  where B.id = #{id}
</select>

你可能想把它映射到一个智能的对象模型,这个对象表示了一篇博客,它由某位作者所写,有很多的博文,每篇博文有零或多条的评论和标签。 我们先来看看下面这个完整的例子,它是一个非常复杂的结果映射(假设作者,博客,博文,评论和标签都是类型别名)。 虽然它看起来令人望而生畏,但其实非常简单。

<!-- 非常复杂的结果映射 -->
<resultMap id="detailedBlogResultMap" type="Blog">
  <constructor>
    <idArg column="blog_id" javaType="int"/>
  </constructor>
  <result property="title" column="blog_title"/>
  <association property="author" javaType="Author">
    <id property="id" column="author_id"/>
    <result property="username" column="author_username"/>
    <result property="password" column="author_password"/>
    <result property="email" column="author_email"/>
    <result property="bio" column="author_bio"/>
    <result property="favouriteSection" column="author_favourite_section"/>
  </association>
  <collection property="posts" ofType="Post">
    <id property="id" column="post_id"/>
    <result property="subject" column="post_subject"/>
    <association property="author" javaType="Author"/>
    <collection property="comments" ofType="Comment">
      <id property="id" column="comment_id"/>
    </collection>
    <collection property="tags" ofType="Tag" >
      <id property="id" column="tag_id"/>
    </collection>
  </collection>
</resultMap>

你现在可能看不懂,接下来我们要学习将多表查询结果使用ResultMap标签映射到实体类对象上!

我们的学习目标:

  1. 多表查询语句使用
  2. 多表结果承接实体类设计
  3. 使用ResultMap完成多表结果映射

1.1 实体类设计方案

多表关系回顾:(双向查看)

  • 一对一
    • 夫妻关系,人和身份证号
  • 一对多| 多对一
    • 用户和用户的订单,锁和钥匙
  • 多对多
    • 老师和学生,部门和员工

实体类设计关系(查询):(单向查看)

  • 对一 : 夫妻一方对应另一方,订单对应用户都是对一关系
    • 实体类设计:对一关系下,类中只要包含单个对方对象类型属性即可!
    • 例如:
public class Customer {

  private Integer customerId;
  private String customerName;

}

public class Order {

  private Integer orderId;
  private String orderName;
  private Customer customer;// 体现的是对一的关系

}  

  • 对多 用户对应的订单,讲师对应的学生或者学生对应的讲师都是对多关系:
  • 实体类设计:对多关系下,类中只要包含对方类型集合属性即可!
public class Customer {

  private Integer customerId;
  private String customerName;
  private List<Order> orderList;// 体现的是对多的关系
}

public class Order {

  private Integer orderId;
  private String orderName;
  private Customer customer;// 体现的是对一的关系
  
}

//查询客户和客户对应的订单集合  不要管!

多表结果实体类设计小技巧:

  • 对一,属性中包含对方对象
  • 对多,属性中包含对方对象集合
  • 只有真实发生多表查询时,才需要设计和修改实体类,否则不提前设计和修改实体类!
  • 无论多少张表联查,实体类设计都是两两考虑!
  • 在查询映射的时候,只需要关注本次查询相关的属性!例如:查询订单和对应的客户,就不要关注客户中的订单集合!

1.2 多表映射案例准备

数据库:

CREATE TABLE `t_customer` (`customer_id` INT NOT NULL AUTO_INCREMENT, `customer_name` CHAR(100), PRIMARY KEY (`customer_id`) );

CREATE TABLE `t_order` ( `order_id` INT NOT NULL AUTO_INCREMENT, `order_name` CHAR(100), `customer_id` INT, PRIMARY KEY (`order_id`) ); 

INSERT INTO `t_customer` (`customer_name`) VALUES ('c01');

INSERT INTO `t_order` (`order_name`, `customer_id`) VALUES ('o1', '1');
INSERT INTO `t_order` (`order_name`, `customer_id`) VALUES ('o2', '1');
INSERT INTO `t_order` (`order_name`, `customer_id`) VALUES ('o3', '1'); 

实际开发时,一般在开发过程中,不给数据库表设置外键约束。

原因是避免调试不方便。

一般是功能开发完成,再加外键约束检查是否有bug。

实体类设计:
稍后会进行订单关联客户查询,也会进行客户关联订单查询,所以在这先练习设计

@Data
public class Customer {

  private Integer customerId;
  private String customerName;
  private List<Order> orderList;// 体现的是对多的关系
  
}  

@Data
public class Order {
  private Integer orderId;
  private String orderName;
  private Customer customer;// 体现的是对一的关系
  
}  

2. 对一映射

  1. 需求说明
    根据ID查询订单,以及订单关联的用户的信息!
  2. OrderMapper接口
public interface OrderMapper {
  Order selectOrderWithCustomer(Integer orderId);
}
  1. OrderMapper.xml配置文件
<!-- 创建resultMap实现“对一”关联关系映射 -->
<!-- id属性:通常设置为这个resultMap所服务的那条SQL语句的id加上“ResultMap” -->
<!-- type属性:要设置为这个resultMap所服务的那条SQL语句最终要返回的类型 -->
<resultMap id="selectOrderWithCustomerResultMap" type="order">

  <!-- 先设置Order自身属性和字段的对应关系 -->
  <id column="order_id" property="orderId"/>

  <result column="order_name" property="orderName"/>

  <!-- 使用association标签配置“对一”关联关系 -->
  <!-- property属性:在Order类中对一的一端进行引用时使用的属性名 -->
  <!-- javaType属性:一的一端类的全类名 -->
  <association property="customer" javaType="customer">

    <!-- 配置Customer类的属性和字段名之间的对应关系 -->
    <id column="customer_id" property="customerId"/>
    <result column="customer_name" property="customerName"/>

  </association>

</resultMap>

<!-- Order selectOrderWithCustomer(Integer orderId); -->
<select id="selectOrderWithCustomer" resultMap="selectOrderWithCustomerResultMap">

  SELECT order_id,order_name,c.customer_id,customer_name
  FROM t_order o
  LEFT JOIN t_customer c
  ON o.customer_id=c.customer_id
  WHERE o.order_id=#{orderId}

</select>

对应关系可以参考下图:
在这里插入图片描述
4. Mybatis全局注册Mapper文件

<!-- 注册Mapper配置文件:告诉Mybatis我们的Mapper配置文件的位置 -->
<mappers>

  <!-- 在mapper标签的resource属性中指定Mapper配置文件以“类路径根目录”为基准的相对路径 -->
  <mapper resource="mappers/OrderMapper.xml"/>

</mappers>
  1. junit测试程序
@Slf4j
public class MyBatisTest {

    private SqlSession session;
    // junit会在每一个@Test方法前执行@BeforeEach方法

    @BeforeEach
    public void init() throws IOException {
        session = new SqlSessionFactoryBuilder()
                .build(
                        Resources.getResourceAsStream("mybatis-config.xml"))
                .openSession();
    }

    @Test
    public void testRelationshipToOne() {
    
      OrderMapper orderMapper = session.getMapper(OrderMapper.class);
      // 查询Order对象,检查是否同时查询了关联的Customer对象
      Order order = orderMapper.selectOrderWithCustomer(2);
      log.info("order = " + order);
    
    }

    // junit会在每一个@Test方法后执行@@AfterEach方法
    @AfterEach
    public void clear() {
        session.commit();
        session.close();
    }
}
  1. 关键词
    在“对一”关联关系中,我们的配置比较多,但是关键词就只有:associationjavaType

3. 对多映射

  1. 需求说明
    查询客户和客户关联的订单信息!
  2. CustomerMapper接口
public interface CustomerMapper {

  Customer selectCustomerWithOrderList(Integer customerId);

}
  1. CustomerMapper.xml文件
<!-- 配置resultMap实现从CustomerOrderList的“对多”关联关系 -->
<resultMap id="selectCustomerWithOrderListResultMap"

  type="customer">

  <!-- 映射Customer本身的属性 -->
  <id column="customer_id" property="customerId"/>

  <result column="customer_name" property="customerName"/>

  <!-- collection标签:映射“对多”的关联关系 -->
  <!-- property属性:在Customer类中,关联“多”的一端的属性名 -->
  <!-- ofType属性:集合属性中元素的类型 -->
  <collection property="orderList" ofType="order">

    <!-- 映射Order的属性 -->
    <id column="order_id" property="orderId"/>

    <result column="order_name" property="orderName"/>

  </collection>

</resultMap>

<!-- Customer selectCustomerWithOrderList(Integer customerId); -->
<select id="selectCustomerWithOrderList" resultMap="selectCustomerWithOrderListResultMap">
  SELECT c.customer_id,c.customer_name,o.order_id,o.order_name
  FROM t_customer c
  LEFT JOIN t_order o
  ON c.customer_id=o.customer_id
  WHERE c.customer_id=#{customerId}
</select>

对应关系可以参考下图:

在这里插入图片描述
4. Mybatis全局注册Mapper文件

<!-- 注册Mapper配置文件:告诉Mybatis我们的Mapper配置文件的位置 -->
<mappers>
  <!-- 在mapper标签的resource属性中指定Mapper配置文件以“类路径根目录”为基准的相对路径 -->
  <mapper resource="mappers/OrderMapper.xml"/>
  <mapper resource="mappers/CustomerMapper.xml"/>
</mappers>
  1. junit测试程序
@Test
public void testRelationshipToMulti() {

  CustomerMapper customerMapper = session.getMapper(CustomerMapper.class);
  // 查询Customer对象同时将关联的Order集合查询出来
  Customer customer = customerMapper.selectCustomerWithOrderList(1);
  log.info("customer.getCustomerId() = " + customer.getCustomerId());
  log.info("customer.getCustomerName() = " + customer.getCustomerName());
  List<Order> orderList = customer.getOrderList();
  for (Order order : orderList) {
    log.info("order = " + order);
  }
}
  1. 关键词
    在“对多”关联关系中,同样有很多配置,但是提炼出来最关键的就是:collectionofType
关联关系配置项关键词所在配置文件和具体位置
对一association标签/javaType属性/property属性Mapper配置文件中的resultMap标签内
对多collection标签/ofType属性/property属性Mapper配置文件中的resultMap标签内

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【FileZilla的安装与使用(主动与被动模式详解,以及如何利用FileZilla搭建FTP服务器并且进行访问)】

目录 一、FileZilla介绍 1.1 简介 1.2 重要信息和功能 二、FileZilla的安装与使用 2.1 FileZilla服务端安装与配置 2.1.1 安装步骤 2.1.2 新建组 2.1.3 新建用户 2.1.4 新建目录 2.1.5 权限分配 &#xff08;1&#xff09;用户Milk权限分配 &#xff08;2&#xff…

HikvisionCamera开发-萤石云RTMP协议获取视频流

RTMP/RTSP&#xff08;实时流传输协议&#xff09;是一种网络协议&#xff0c;旨在用于传输音频和视频数据。本文将介绍如何在HikvisionCamera二次开发中如何通过RTMP协议获得实时视频流&#xff0c;使用到的摄像头为POE供电的海康威视-臻全彩款&#xff0c;以及套餐内配套录像…

JMeter使用

目录 启动JMeter 创建线程组 设置线程参数 设置http请求参数 ​编辑 创建查看结果树(显示成功/失败多少以及返回结果等信息) 创建聚合报告(显示响应时间、吞吐量、异常数等信息) 点击上方的执行按钮即可开始压力测试 结果树显示 聚合报告结果显示 启动JMeter 在JMete…

【NLP论文】03 基于 jiagu 的情感分析

本篇是NLP论文系列的最后一篇&#xff0c;主要介绍如何计算情感分析结果&#xff0c;并将其融入到XX评价体系和物流关键词词库&#xff0c;之前我已经写了两篇关于情感分析的文章&#xff0c;分别是 SnowNLP 和 Cemotion 技术&#xff0c;最终我才用了 jiagu 来写我的论文&…

机器人中的数值优化之线性共轭梯度法

欢迎大家关注我的B站&#xff1a; 偷吃薯片的Zheng同学的个人空间-偷吃薯片的Zheng同学个人主页-哔哩哔哩视频 (bilibili.com) 本文ppt来自深蓝学院《机器人中的数值优化》 目录 1.无约束优化方法对比 2.Hessian-vec product 3.线性共轭梯度方法的步长​编辑 4.共轭梯度…

mac上使用Navicat Premium 在本地和生产环境中保持数据库同步

Navicat Premium 是一款功能强大的数据库管理和开发工具&#xff0c;支持多种数据库系统&#xff0c;如 MySQL、Oracle、SQL Server 等。作为程序员&#xff0c;我深知在开发过程中需要一款方便、高效的数据库管理工具来提升工作效率。而 Navicat Premium 正是这样一款不可多得…

Spring Boot学习随笔- Jasypt加密数据库用户名和密码以及解密

学习视频&#xff1a;【编程不良人】2021年SpringBoot最新最全教程 第十九章、Jasypt加密 Jasypt全称是Java Simplified Encryption&#xff0c;是一个开源项目。 Jasypt与Spring Boot集成&#xff0c;以便在应用程序的属性文件中加密敏感信息&#xff0c;然后在应用程序运行…

怎么解决 Nginx反向代理加载速度慢?

Nginx反向代理加载速度慢可能由多种原因引起&#xff0c;以下是一些可能的解决方法&#xff1a; 1&#xff0c;网络延迟&#xff1a; 检查目标服务器的网络状况&#xff0c;确保其网络连接正常。如果目标服务器位于不同的地理位置&#xff0c;可能会有较大的网络延迟。考虑使用…

从0到1快速入门ETLCloud

一、ETLCloud的介绍 ETL是将业务系统的数据经过抽取&#xff08;Extract&#xff09;、清洗转换&#xff08;Transform&#xff09;之后加载&#xff08;Load&#xff09;到数据仓库的过程&#xff0c;目的是将企业中的分散、凌乱、标准不统一的数据整合到一起&#xff0c;为企…

【C#】知识点实践序列之Lock的输出多线程信息

大家好&#xff0c;我是全栈小5&#xff0c;欢迎来到《小5讲堂之知识点实践序列》文章。 2023年第2篇文章&#xff0c;此篇文章是C#知识点实践序列之Lock知识点&#xff0c;博主能力有限&#xff0c;理解水平有限&#xff0c;若有不对之处望指正&#xff01; 本篇在Lock锁定代码…

【力扣题解】P700-二叉搜索树中的搜索-Java题解

&#x1f468;‍&#x1f4bb;博客主页&#xff1a;花无缺 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! 本文由 花无缺 原创 收录于专栏 【力扣题解】 文章目录 【力扣题解】P700-二叉搜索树中的搜索-Java题解&#x1f30f;题目描述&#x1f4a1;题解&#x1f…

D45D46|动态规划之子序列问题

300.最长递增子序列&#xff1a; 初始思路&#xff1a; 动态规划五部曲&#xff1a; 1&#xff09;dp数组的定义&#xff0c;dp[i]表述数组第i个元素大于前面几个值&#xff1b; 2&#xff09;dp数组的迭代&#xff0c;min nums[x]表示递增数组中的最后一个值&#xff0c;如…

Linux 安装 mysql【使用yum源进行安装】

配置yum 源 首先&#xff0c;去到mysql网站&#xff0c;找到它的rpm的资源包 “mysql80-community-release-el9-5.noarch.rpm” 我们将其下载下来&#xff0c;然后配置yum源&#xff08;下面两种方式二选一即可&#xff09; ① 使用xftp传输&#xff0c;然后配置yum源 rpm …

【数据结构】栈和队列(队列的基本操作和基础知识)

&#x1f308;个人主页&#xff1a;秦jh__https://blog.csdn.net/qinjh_?spm1010.2135.3001.5343&#x1f525; 系列专栏&#xff1a;《数据结构》https://blog.csdn.net/qinjh_/category_12536791.html?spm1001.2014.3001.5482 ​ 目录 前言 队列 队列的概念和结构 队列的…

王道考研计算机网络——应用层

如何为用户提供服务&#xff1f; CS/P2P 提高域名解析的速度&#xff1a;local name server高速缓存&#xff1a;直接地址映射/低级的域名服务器的地址 本机也有告诉缓存&#xff1a;本机开机的时候从本地域名服务器当中下载域名和地址的对应数据库&#xff0c;放到本地的高…

FDM3D打印系列——RX-78-2高达胸像打印

https://v.youku.com/v_show/id_XNjI4OTQ2NjkyNA.html   大家好&#xff0c;我是阿赵。   2024年的第一篇博客&#xff0c;做一个3D打印作品&#xff0c;RX-78-2高达胸像打印。 成年男人是很少收得到礼物的&#xff0c;所以礼物都要自己准备。这个模型&#xff0c;就算是我…

Javaweb之Mybatis入门程序的详细解析

1.2 入门程序实现 1.2.1 准备工作 1.2.1.1 创建springboot工程 创建springboot工程&#xff0c;并导入 mybatis的起步依赖、mysql的驱动包。 项目工程创建完成后&#xff0c;自动在pom.xml文件中&#xff0c;导入Mybatis依赖和MySQL驱动依赖 <!-- 仅供参考&#xff1a;只…

数据库——建立ER模型及关系模型转换

​ 【实验内容及要求】 使用画图工具或MySQL Workbench等建模工具设计出相应的ER图&#xff0c;将局部ER图合并为一个整体ER模型&#xff0c;在ER模型中填加多样性约束&#xff0c;建立显示主键的ER模型&#xff0c;标识实体的属性&#xff0c;确认主键、外键。将上述ER图转化…

基于 LightGBM 的系统访问风险识别

基于 LightGBM 的系统访问风险识别 文章目录 基于 LightGBM 的系统访问风险识别一、课题来源二、任务描述三、课题背景四、数据获取分析及说明&#xff08;1&#xff09;登录https://www.datafountain.cn并获取相关数据&#xff08;2&#xff09;数据集文件说明&#xff08;3&a…

pycharm python环境安装

目录 1.Python安装 2.PyQt5介绍 3.安装pyuic 4.启动designer.exe 5.pyinstaller(打包发布程序) 6.指定源安装 7.PyQt5-tools安装失败处理 8.控件介绍 9.错误记录 1.NameError: name reload is not defined 10.开发记录 重写报文输出和文件 ​编辑 1.Python安装 点…