MyBatis多表映射

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标签内

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

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

相关文章

二叉树详解(深度优先遍历、前序,中序,后序、广度优先遍历、二叉树所有节点的个数、叶节点的个数)

目录 一、树概念及结构(了解) 1.1树的概念 1.2树的表示 二、二叉树概念及结构 2.1概念 2.2现实中的二叉树&#xff1a; 2.3数据结构中的二叉树&#xff1a; 2.4特殊的二叉树&#xff1a; 2.5 二叉树的存储结构 2.51 顺序存储&#xff1a; 2.5.2 链式存储&…

【快速全面掌握 WAMPServer】09.如何在 WAMPServer 中安装 Composer

网管小贾 / sysadm.cc WAMPServer 的大名想必应该有不少人特别是新手小白们略有耳闻吧。 它是出自法国大神之手的一款 PHP 开发环境集成包&#xff0c;工作于 Windows 环境&#xff0c;类似于它这样的集成包在 Linux 平台上反正我是没找到&#xff0c;所以它应该算是对使用 Wi…

sparkstreamnig实时处理入门

1.2 SparkStreaming实时处理入门 1.2.1 工程创建 导入maven依赖 <dependency><groupId>org.apache.spark</groupId><artifactId>spark-streaming_2.12</artifactId><version>3.1.2</version> </dependency> <dependency…

【MySQL表的增删查改】

文章目录 前言1 Create1.1 单行数据 全列插入1.2 多行数据 指定列插入1.3 插入否则更新1.4 替换 2 Retrieve2.1 SELECT 列2.1.1 全列查询2.1.2 指定列查询2.1.3 查询字段为表达式2.1.4 为查询结果指定别名2.1.5 结果去重 2.2 WHERE 条件2.2.1 英语不及格的同学及英语成绩 ( &…

CocoaPods安装及‘__rvm_make -j8‘处理

CocoaPods是一个用Ruby写的、负责管理iOS项目中第三方开源库的工具&#xff0c;CocoaPods能让我们集中的、统一管理第三方开源库&#xff0c;为我们节省设置和更新第三方开源库的时间。 安装步骤 1.查看ruby版本 ruby -v 2.通过rvm来安装或升级Ruby&#xff0c;依次执行 cu…

Apache OFBiz RCE漏洞复现(CVE-2023-51467)

0x01 产品简介 Apache OFBiz是一个电子商务平台,用于构建大中型企业级、跨平台、跨数据库、跨应用服务器的多层、分布式电子商务类应用系统。 0x02 漏洞概述 漏洞成因 该系统的身份验证机制存在缺陷,可能允许未授权用户通过绕过标准登录流程来获取后台访问权限。此外,在…

【PTA-C语言】实验七-函数与指针I

如果代码存在问题&#xff0c;麻烦大家指正 ~ ~有帮助麻烦点个赞 ~ ~ 目录——实验七-函数与指针I 6-1 弹球距离&#xff08;分数 10&#xff09;6-2 使用函数输出一个整数的逆序数&#xff08;分数 10&#xff09;6-3 使用函数求最大公约数&#xff08;分数 10&#xff09;6-4…

使用Pycharm给html文件添加浏览器

1、选择菜单栏的File---->选择setting设置 2、选择Tools(工具)---> Web Browser(web 浏览器) 勾选 自己想要添加的浏览器前面 的勾选框即可 注意点击ok进行保存

《数据结构、算法与应用C++语言描述》- 平衡搜索树 -全网唯一完整详细实现插入和删除操作的模板类

平衡搜索树 完整可编译运行代码见&#xff1a;Github::Data-Structures-Algorithms-and-Applications/_34Balanced search tree 概述 本章会讲AVL、红-黑树、分裂树、B-树。 平衡搜索树的应用&#xff1f; AVL 和红-黑树和分裂树适合内部存储的应用。 B-树适合外部存储的…

github使用技巧(经验篇)

相关经验 指定代码范围并高亮显示 例如&#xff0c;指定nn_ops.py文件2612-L2686行的代码&#xff1a;https://github.com/tensorflow/tensorflow/blob/v2.14.0/tensorflow/python/ops/nn_ops.py#L2612-L2686 FAQ Q&#xff1a;github网页打不开&#xff1f; 【github加载不…

Java项目调试实战:如何高效调试Spring Boot项目中的GET请求,并通过equalsIgnoreCase()解决大小写不一致问题

Java项目调试实战&#xff1a;如何高效调试Spring Boot项目中的GET请求&#xff0c;并通过equalsIgnoreCase解决大小写不一致问题 写在最前面全部过程Java equalsIgnoreCase() 方法idea中如何调试SpringBoot项目在IntelliJ IDEA中使用内置HTTP客户端设置断点和调试 补充&#x…

PiflowX组件-WriteToUpsertKafka

WriteToUpsertKafka组件 组件说明 以upsert方式往Kafka topic中写数据。 计算引擎 flink 有界性 Streaming Upsert Mode 组件分组 kafka 端口 Inport&#xff1a;默认端口 outport&#xff1a;默认端口 组件属性 名称展示名称默认值允许值是否必填描述例子kafka_h…

Unity坦克大战开发全流程——结束场景——通关界面

结束场景——通关界面 就照着这样来拼 写代码 hideme不要忘了 修改上一节课中的代码

旅游网站Xtrip 前端模板html推荐

一、需求分析 旅游网站的功能可以根据具体的业务需求和目标进行不同的设计和实现&#xff0c;但是以下是一些常见的旅游网站功能&#xff0c;供参考&#xff1a; 酒店预订功能&#xff1a;用户可以搜索并预订酒店&#xff0c;查看酒店的详细信息、价格、评价和照片&#xff0c…

MySQL 8.0 InnoDB Tablespaces之General Tablespaces(通用表空间/一般表空间)

文章目录 MySQL 8.0 InnoDB Tablespaces之General Tablespaces&#xff08;通用表空间/一般表空间&#xff09;General tablespaces&#xff08;通用表空间/一般表空间&#xff09;通用表空间的功能通用表空间的限制 创建通用表空间&#xff08;一般表空间&#xff09;创建语法…

Linux磁盘与文件管理

目录 一、磁盘介绍 1. 磁盘数据结构 2. 磁盘的接口类型 3. 磁盘在Linux上的表现形式 二、磁盘分区与MBR 1. 分区优缺点 2. 分区方式 3. MBR分区 4. GPT分区 三、文件系统 1. 文件系统的组成 2. 默认的文件系统 3. 文件系统的作用 4. 模拟破坏文件与修复文件 4…

项目总结报告

《项目总结报告》 1.项目概要&#xff08;项目基本信息&#xff0c;项目期间&#xff0c;项目成果&#xff0c;项目开发工具环境&#xff09; 2.项目工作分析&#xff08;需求变更&#xff0c;计划与进度实施&#xff0c;投入情况&#xff0c;收益情况&#xff0c;质量情况&…

【Linux】Linux 下基本指令 -- 详解

无论是什么命令&#xff0c;用于什么用途&#xff0c;在 Linux 中&#xff0c;命令有其通用的格式&#xff1a; command [-options] [parameter] command&#xff1a;命令本身。-options&#xff1a;[可选&#xff0c;非必填]命令的一些选项&#xff0c;可以通过选项控制命令的…

navicat premium历史版本下载及更新navicat premium15 永久(使用)有效期

1、navicat premium介绍 Navicat Premium 是一套可创建多个连接的数据库开发工具&#xff0c;让你从单一应用程序中同时连接 MySQL、Redis、MariaDB、MongoDB、SQL Server、Oracle、PostgreSQL 和 SQLite 。它与 GaussDB 、OceanBase 数据库及 Amazon RDS、Amazon Aurora、Amaz…

windows和linux操作Git(序章2)

Git 分布式版本控制系统(序章1) ## Linux 下安装 Git&#x1f53a; ​ ## Git命令大全&#x1f53a; windows和linux通用 安装完 Git 后&#xff0c;需要进行配置&#xff0c;如姓名、Email 等 git config --global user.name "你的名字"git config --global us…