MyBatis的多表操作

news2024/10/6 2:24:41

1 MyBatis的多表操作

1.1 多表模型介绍

我们之前学习的都是基于单表操作的,而实际开发中,随着业务难度的加深,肯定需要多表操作的。

  • 多表模型分类 一对一:在任意一方建立外键,关联对方的主键。

  • 一对多:在多的一方建立外键,关联一的一方的主键。

  • 多对多:借助中间表,中间表至少两个字段,分别关联两张表的主键。

1.2 多表模型一对一操作

  1. 一对一模型: 人和身份证,一个人只有一个身份证

  2. 代码实现运行结果:

    1. 步骤一: sql语句准备
CREATE TABLE person(    
id INT PRIMARY KEY AUTO_INCREMENT,    
NAME VARCHAR(20),    
age INT);
INSERT INTO person VALUES (NULL,'张三',23);
INSERT INTO person VALUES (NULL,'李四',24);
INSERT INTO person VALUES (NULL,'王五',25);CREATE TABLE card(    
id INT PRIMARY KEY AUTO_INCREMENT,    
 number VARCHAR(30),   
 pid INT,    
CONSTRAINT cp_fk FOREIGN KEY (pid) REFERENCES person(id));

INSERT INTO card VALUES (NULL,'12345',1);INSERT INTO card VALUES (NULL,'23456',2);INSERT INTO card VALUES (NULL,'34567',3);

创建实体对象

@Data
public class Card {
    private int id;
    private int number;
    private int pid;  // 可以不写
    private Person p;

}
@Data
public class Person {
    private int id;
    private String name;
    private int age;
}

步骤二:编写dao接口

public interface OneToOneDao {
    //查询全部card数据
    public List<Card> findAll();
}

步骤三:配置文件

<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.zxy.dao.OneToOneDao">
    <!--配置字段和实体对象属性的映射关系-->
    <resultMap id="oneToOne" type="card">
        <id column="cid" property="id"/>
        <result property="number" column="number"/>
		<!--实体类里面不包含 pid属性的话不需要这一句话-->
		<result property="pid" column="cpid"/>

        <!--
           association:配置被包含对象的映射关系
           property:被包含对象的变量名
           javaType:被包含对象的数据类型
       -->
        <association property="p" javaType="person">
            <id column="pid" property="id"/>
            <result property="name" column="name"/>
            <result property="age" column="age"/>
        </association>
    </resultMap>

<!--    查询数据-->
    <select id="findAll" resultMap="oneToOne">
	// 实体没有pid属性的时候使用以下语句
        select c.id cid,number,pid,name,age  from card c,person p where c.pid=p.id

	//包含pid属性的时候使用以下语句
    select  c.id cid,c.pid cpid,number,pid,name,age from card c , person p where c.pid=p.id


    </select>
</mapper>

步骤四:配置核心配置文件

<mapper resource="cn/zxy/dao/onetoOneDao.xml"/>

步骤五:测试类

@Test
        public void onetest(){
            SqlSession sqlSession = MybatisUtils.getSqlSession(true);
            //获取UserDao接口实现类对象
           OneToOneDao mapper = sqlSession.getMapper(OneToOneDao.class);
            List<Card> list = mapper.findAll();
            for (Card card : list) {
                System.out.println(card);
            }
            MybatisUtils.closeSqlSession(sqlSession);
        }

运行结果:

在这里插入图片描述

一对一配置总结

<resultMap>:配置字段和对象属性的映射关系标签。
    id 属性:唯一标识
    type 属性:实体对象类型
<id>:配置主键映射关系标签。
<result>:配置非主键映射关系标签。
    column 属性:表中字段名称
    property 属性: 实体对象变量名称
<association>:配置被包含对象的映射关系标签。
    property 属性:被包含对象的变量名
    javaType 属性:被包含对象的数据类型

1.3 多表模型一对多操作

  1. 一对多模型: 一对多模型:班级和学生,一个班级可以有多个学生。

  2. 代码实现

    1. 步骤一: sql语句准备
CREATE TABLE classes(
	id INT PRIMARY KEY AUTO_INCREMENT,
	NAME VARCHAR(20)
);
INSERT INTO classes VALUES (NULL,'211一等班级');
INSERT INTO classes VALUES (NULL,'211二等班级');

CREATE TABLE student(
	id INT PRIMARY KEY AUTO_INCREMENT,
	NAME VARCHAR(30),
	age INT,
	cid INT,
	CONSTRAINT cs_fk FOREIGN KEY (cid) REFERENCES classes(id)
);
INSERT INTO student VALUES (NULL,'张三',23,1);
INSERT INTO student VALUES (NULL,'李四',24,1);
INSERT INTO student VALUES (NULL,'王五',25,2);
INSERT INTO student VALUES (NULL,'赵六',26,2);

实体类准备

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Classes {
    private Integer id;     //主键id
    private String name;    //班级名称

    private List<Student> students; //班级中所有学生对象
    
}
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student {
    private Integer id;     //主键id
    private String name;    //学生姓名
    private Integer age;    //学生年龄
}

步骤二:添加dao接口对象

public interface OneToManyDao {
    public List<Classes> findAll();
}

步骤三:配置文件

<mapper namespace="com.by.dao.OneToManyDao">
   <resultMap id="oneToMany" type="classes">
    <id column="cid" property="id"/>
   <result column="name" property="name"/>
       <!--
                  collection:配置被包含的集合对象映射关系
                  property:被包含对象的变量名
                  ofType:被包含对象的实际数据类型
              -->
    <collection property="students" ofType="student">
        <id column="sid" property="id"></id>
        <result column="name" property="name"/>
        <result column="age" property="age"/>
    </collection>
   </resultMap>
<select id="findAll" resultMap="oneToMany">
    select c.id cid,c.name,s.id sid,s.name,s.age  from classes c,student s where c.id=s.cid
</select>
</mapper>

步骤四:配置核心文件

<mapper resource="com/by/dao/OneToManyDao.xml"/>

步骤五:测试类

 @Test
    public void onemanytest(){
        SqlSession sqlSession = MybatisUtils.getSqlSession(true);
        //获取UserDao接口实现类对象
        OneToManyMapper mapper = sqlSession.getMapper(OneToManyMapper.class);
        List<Classes> list = mapper.findAll();
        for (Classes classes : list) {
            System.out.println(classes);
        }
        MybatisUtils.closeSqlSession(sqlSession);
    }

一对多配置文件总结:

<resultMap>:配置字段和对象属性的映射关系标签。
    id 属性:唯一标识
    type 属性:实体对象类型
<id>:配置主键映射关系标签。
<result>:配置非主键映射关系标签。
    column 属性:表中字段名称
    property 属性: 实体对象变量名称
<collection>:配置被包含集合对象的映射关系标签。
    property 属性:被包含集合对象的变量名
    ofType 属性:集合中保存的对象数据类型

什么是延迟加载?

问题

在开发过程中很多时候我们并不需要总是在加载用户信息时就一定要加载他的订单信息,此时就是我们所说的延迟加载

举个例子

*在一对多中,当我们有一个用户,它有个100个订单
在查询用户的时候,要不要把关联的订单查出来?
在查询订单的时候,要不要把关联的用户查出来?
* 回答
在查询用户时,用户下的订单应该是,什么时候用,什么时候查询。
在查询订单时,订单所属的用户信息应该是随着订单一起查询出来。

延迟加载

就是在需要用到数据时才进行加载,不需要用到数据时就不加载数据
延迟加载也称懒加载。

优点:
   先从单表查询,需要时再从关联表去关联查询,⼤⼤提⾼数据库性能,因为查询单表要比关联查询多张表速度要快。
缺点:
   因为只有当需要用到数据时,才会进行数据库查询,这样在大批量数据查询时,因为查询工作也要消耗时间,所以可能造成⽤户等待时间变长,造成用户体验下降。
在多表中:
     一对多,多对多:通常情况下采用延迟加载
     一对一(多对一):通常情况下采用立即加载
注意:
延迟加载是基于嵌套查询来实现的 

局部延迟加载实现:

一对一延迟加载:

创建Personmapper接口

public interface PersonMapper {

    public List<Person> findById(Integer id);
}

创建mapper映射文件:

<mapper namespace="cn.zxy.mapper.PersonMapper">

    <select id="findById" resultType="person">
        select * from person where id=#{id}
    </select>
</mapper>

修改一对一映射文件:

<mapper namespace="cn.zxy.mapper.OneToOneMapper">
    <!--配置字段和实体的关系 映射关系-->
    <resultMap id="OneToOne" type="card">
        <id property="id" column="id"/>
        <result property="number" column="number"/>
        <result property="pid" column="pid"/>
 
        <!--
           fetchType 延迟加载 lazy 指的是懒加载
                    eager 指的是默认立即加载
            select 是查询关键字 查询mapper接口里面的findById
            如果使用全局的延迟加载 那么就把fetchType 去掉,然后全局配置必须是true才开启延迟加载
        -->
        <association property="p" column="pid" javaType="person"
        select="cn.zxy.mapper.PersonMapper.findById" fetchType="lazy">

        </association>

    </resultMap>
    <!--需要两个mapper映射文件配合使用-->
    <select id="findAll" resultMap="OneToOne">
        select * from card
    </select>
</mapper>

一对多延迟加载

创建StuMapper接口:

public interface StudentMapper {

    public List<Student> findByCid(Integer id);
}

创建StuMapper映射文件:

<mapper namespace="cn.zxy.mapper.StudentMapper">

    <select id="findByCid" resultType="student">
        select * from student where cid=#{id}
    </select>
</mapper>

修改一对多映射文件:

<mapper namespace="cn.zxy.mapper.OneToManyMapper">
    <resultMap id="oneToMany" type="classes">
        <id column="id" property="id"/>
        <result column="name" property="name"/>
   

        <!--延迟加载 使用全局的延迟模式-->

      <collection property="stu" column="id" ofType="student"
      select="cn.zxy.mapper.StudentMapper.findByCid" fetchType="eager">

        </collection>

    </resultMap>
    <select id="findAll" resultMap="oneToMany">
        select * from classes
    </select>


</mapper>

延迟加载的原理:

延迟加载主要是通过动态代理的形式实现,通过代理拦截到指定方法,执行数据加载。
在这里插入图片描述

1.4 多表模型多对多操作

多对多模型:学生和课程,一个学生可以选择多门课程、一个课程也可以被多个学生所选择。

代码实现

  • 步骤一: sql语句准备
CREATE TABLE course(
	id INT PRIMARY KEY AUTO_INCREMENT,
	NAME VARCHAR(20)
);
INSERT INTO course VALUES (NULL,'语文');
INSERT INTO course VALUES (NULL,'数学');


CREATE TABLE stu_cr(
	id INT PRIMARY KEY AUTO_INCREMENT,
	sid INT,
	cid INT,
	CONSTRAINT sc_fk1 FOREIGN KEY (sid) REFERENCES student(id),
	CONSTRAINT sc_fk2 FOREIGN KEY (cid) REFERENCES course(id)
);
INSERT INTO stu_cr VALUES (NULL,1,1);
INSERT INTO stu_cr VALUES (NULL,1,2);
INSERT INTO stu_cr VALUES (NULL,2,1);
INSERT INTO stu_cr VALUES (NULL,2,2);

  • 步骤二:实体类准备
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Course {
    private Integer id;     //主键id
    private String name;    //课程名称
 
}
student类里面添加 课程集合
    
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student {
    private Integer id;     //主键id
    private String name;    //学生姓名
    private Integer age;    //学生年龄
    private List<Course> courses;   // 学生所选择的课程集合
}

步骤三:创建dao接口

public interface ManyToManyDao {
    //查询学生全部数据 得到课表和班级
    public List<Student> findAll();
}

步骤四:配置文件

  • 数据库字段分析:
select sc.sid scid,s.id sid,s.name,s.age,c.id cid,c.name cname ,sc.id from student s, course c, stu_cr sc where sc.sid=s.id and s.cid=c.id
  • 映射文件编写
<mapper namespace="cn.zxy.dao.ManyToManyDao">
    <resultMap id="manyToMany" type="student">
        <id column="sid" property="id"/>
        <result column="sname" property="name"/>
        <result column="sage" property="age"/>
        <!--
            property 指的是student里面定义的集合变量名
            ofType 指的是实体类对象
           -->
        <collection property="courses" ofType="course">
            <id column="cid" property="id"/>
            <result column="cname" property="name"/>
        </collection>
    </resultMap>
<select id="findAll" resultMap="manyToMany">
    select  sc.sid,s.name sname, s.age sage,c.name cname,sc.cid  from student s,course c,stu_cr sc where sc.sid=s.id and sc.cid=c.id
</select>
</mapper>

步骤五:测试类

@Test
    public void manytoTest(){
        SqlSession sqlSession = MybatisUtils.getSqlSession(true);
        //获取UserDao接口实现类对象
        ManyToManyDao mapper = sqlSession.getMapper(ManyToManyDao.class);
        List<Student> manylist = mapper.findAll();
        for (Student student : manylist) {
            System.out.println(student);
        }
        MybatisUtils.closeSqlSession(sqlSession);
    }

1.5 多表模型操作总结

<resultMap>:配置字段和对象属性的映射关系标签。
    id 属性:唯一标识
    type 属性:实体对象类型
<id>:配置主键映射关系标签。
<result>:配置非主键映射关系标签。
    column 属性:表中字段名称
    property 属性: 实体对象变量名称
<association>:配置被包含对象的映射关系标签。
    property 属性:被包含对象的变量名
    javaType 属性:被包含对象的数据类型
<collection>:配置被包含集合对象的映射关系标签。
    property 属性:被包含集合对象的变量名
    ofType 属性:集合中保存的对象数据类型

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

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

相关文章

IDEA 工具- Java - Tomcat 9.x - 无法使用外部 tomcat 服务器的断点测试功能

问题&#xff1a;使用外部 Tomcat 运行项目&#xff0c;却无法使用断点功能测试 Java 项目 解决方法&#xff1a; 在 IDEA 工具的tomcat Edit configurations&#xff0c;进行修改 具体配置位置&#xff1a; Environment Variables 配置选项添加内容&#xff1a; NameValueJ…

Unity游戏源码分享-线条圆圈游戏Line and Circle Game Template

Unity游戏源码分享-线条圆圈游戏Line and Circle Game Template 圆圈穿过线条就通关 工程地址&#xff1a; https://download.csdn.net/download/Highning0007/88061484

java学习路程之篇十、知识点、数组介绍、二维数组介绍、静态初始化、访问元素、遍历元素、动态初始化、内存图、数组常见问题

文章目录 01、数组介绍02、数组静态初始化03、数组元素访问04、数组遍历操作05、数组动态初始化06、数组内存图07、数组常见问题08、二维数组介绍09、二维数组静态初始化10、二维数组遍历11、二维数组动态初始化12、二维数组内存图 01、数组介绍 02、数组静态初始化 03、数组元…

封装 视频以及监控组件

1.引入插件。 文件Git 地址&#xff1a; https://gitee.com/wang-xiaowang123/liveplayer.html 文件中 <script src"/assets/js/liveplayer-lib.min.js" exclude></script> // liveplayer-lib.min.js 文件在Git仓库中2.封装组件 LivePlayerDemo.vue …

php做网页版剪刀石头布的功能

实例讲述了php实现的网页版剪刀石头布攻略在玩游网上的设计。分享给大家供大家参考&#xff0c;具体如下&#xff1a; <?php /* * Created on 2016-11-25 * */ if (isset($_POST[sub])) { $what $_POST[what]; //需要输入的数组 $my_array array("剪刀","…

算法通关村第一关-链表青铜挑战笔记

文章目录 前言一、Java的链表是怎么构造的&#xff1f;单链表的构造简介&#xff1a; 构造链表&#xff1a; 链表增加元素&#xff0c;首部&#xff0c;中间和尾部分别会有什么问题&#xff0c;需要怎么处理&#xff1f;链表的新增在头部添加元素&#xff1a;在中间添加元素&am…

IP库新增多种颜色转换空间IP

颜色空间转换是图像及视频中常用的解决方案&#xff0c;涉及hsv-rgb、rgb-ycrcb等一些常见的颜色空间互相转换&#xff0c;今天带来几种常见的颜色空间转换IP&#xff0c;主要如下&#xff1a; IP库简介 一直想做一个可以供大家学习、使用的开源IP库&#xff0c;类似OpenCores&…

美化图表——LiveCharts中的时序图的制作,相对问题的解决

美化图表——LiveCharts中的时序图的制作&#xff0c;相应问题的解决 前言一、效果展示二、基本的一些实现的代码1.X,Y坐标的相关设置2.新增波形对象3.实时更新数据 三、修改的点总结 前言 在项目中&#xff0c;需要用到图表来展示波形的实时变化&#xff0c;故找到了这个Live…

优维低代码实践:统计视图

优维低代码技术专栏&#xff0c;是一个全新的、技术为主的专栏&#xff0c;由优维技术委员会成员执笔&#xff0c;基于优维7年低代码技术研发及运维成果&#xff0c;主要介绍低代码相关的技术原理及架构逻辑&#xff0c;目的是给广大运维人提供一个技术交流与学习的平台。 优维…

35.Vue自定义指令-总结

目录 1.自定义指令容易踩的坑 1.1 指令名如果是多个单词&#xff0c;要使用kebab-case命名方式&#xff0c;不要用camelCase命名 1.2 指令回调函数中的this问题 1.3 局部指令与全局指令 2.自定义指令总结 2.1 定义语法&#xff1a; (1).局部指令 (2).全局指令 2.2 配置…

3.14 Bootstrap 缩略图

文章目录 Bootstrap 缩略图添加自定义的内容 Bootstrap 缩略图 本章将讲解 Bootstrap 缩略图。大多数站点都需要在网格中布局图像、视频、文本等。Bootstrap 通过缩略图为此提供了一种简便的方式。使用 Bootstrap 创建缩略图的步骤如下&#xff1a; 在图像周围添加带有 class …

ChatGPT | 修改RetrievalQA推荐答案的数量

知识库经常遇到一个问题会在一个文件的多处或者多个文件出现&#xff0c;这时候如果只回答一个结果就欠佳&#xff0c;最理想的做法是模仿推荐功能&#xff0c;把合适的多个答案及其出处汇总给用户。 如图&#xff0c;一个接口文档里面提到多处“http请求URL”&#xff1a; 使…

vue项目如何部署?有遇到布署服务器后刷新404问题吗?

一、如何部署 前后端分离开发模式下,前后端是独立布署的,前端只需要将最后的构建物上传至目标服务器的web容器指定的静态目录下即可 我们知道vue项目在构建后,是生成一系列的静态文件

Minecraft 1.20.x Forge模组开发 01.Idea开发环境配置

我们本次来进行Minecraft 1.20.x 模组开发环境配置教程的介绍。 效果演示 效果演示 效果演示 1.首先我们需要下载Java17和1.20模组开发包: Java17下载官网

csdn新星计划vue3+ts+antd赛道——利用inscode搭建vue3(ts)+antd前端模板

文章目录 ⭐前言⭐利用inscode免费开放资源&#x1f496; 在inscode搭建vue3tsant项目&#x1f496; 调整配置&#x1f496; antd 国际化配置&#x1f496; 用户store&#x1f496; 路由权限&#x1f496; 预览 ⭐结束 ⭐前言 大家好&#xff0c;我是yma16&#xff0c;本文分享…

【字节流】读数据(一次读一个字节数组数据)

字节流读数据&#xff08;一次读一个字节数组数据&#xff09; 1.需求&#xff1a; 把文件fos.txt中的内容读取出来在控制台输出 2.思路&#xff1a; 创建字节输入流对象调用字节输入流对象的读数据方法释放资源 package com.bytestream; import java.io.FileInputStream; …

TCP/IP网络编程 第十五章:套接字和标准I/O

标准I/O函数的优点 标准I/O函数的两个优点 将标准I/O函数用于数据通信并非难事。但仅掌握函数使用方法并没有太大意义&#xff0c;至少应该 了解这些函数具有的优点。下面列出的是标准I/O函数的两大优点: □标准I/O函数具有良好的移植性(Portability) □标准I/O函数可以利用缓…

stable diffusion windows本地搭建的坑

刚刚2小时前&#xff0c;我搭好了&#xff0c;欣喜若狂&#xff0c;开放端口&#xff0c;同事也尝试了。我的配置 16G内存&#xff0c;AMD卡&#xff0c;有gpu但是没有用。这里不说具体步骤&#xff0c;只说坑点。 首先就是安装gfpgan、clip、openclip问题&#xff0c;我参考…

短视频seo矩阵系统源码开发部署

目录 短视频矩阵源码部署步骤简单易懂&#xff0c;开发者只需按照以下几个步骤进行操作&#xff1a; 代码展示---seo关键词分析 开发要点&#xff1a; 代码展示如下&#xff1a; 开发部署注意事项&#xff1a; 说明&#xff1a;本开发文档适用于短视频seo矩阵系统源码开发…

如何理解 dutu输光定理

解决问题 1 dutu 拿100是赌一次好&#xff0c;还是100次1元的好&#xff1f; 一般的地方&#xff0c;如果不是公平赌局&#xff0c;而期望是负数的话 其实du次数越多越亏 2 1%就基本能决定胜负 了 3 千万不要陷入常人思维&#xff0c;用筹码数量思考&#xff0c;输光为止&am…