MyBatis:关联查询

news2024/11/15 21:23:35

MyBatis

  • 前言
  • 关联查询
      • 懒加载
      • 对象为集合时的关联查询

在这里插入图片描述

前言

MyBatis:配置文件 文章中,最后介绍了可以使用 select 标签的 resultMap 属性实现关联查询,下面简单示例

关联查询

首先,先创建 association_role 和 association_user 两张数据表,并建立关联关系
表结构如图:
在这里插入图片描述
表信息如图:
在这里插入图片描述

在创建 association_user 表时需要添加 association_role 表的关联字段( role_id )
表结构如图:
在这里插入图片描述
表信息如图:
在这里插入图片描述

接着,创建与两张数据表一一映射的实体类 AssociationRole 和 AssociationUser

// AssociationRole
package cn.edu.MyBatisDemo.model;

public class AssociationRole {
    private int id;
    private String role;

    public AssociationRole() {
        super();
    }

    public AssociationRole(int id, String role) {
        this.id = id;
        this.role = role;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getRole() {
        return role;
    }

    public void setRole(String role) {
        this.role = role;
    }

    @Override
    public String toString() {
        return "AssociationRole{" +
                "id=" + id +
                ", role='" + role + '\'' +
                '}';
    }
}
// AssociationUser
package cn.edu.MyBatisDemo.model;

public class AssociationUser {
    private int id;
    private String name;

    //添加 AssociationRole 属性
    private AssociationRole role; // AssociationRole -- 1:m -- AssociationUser (一对多关系)

    public AssociationUser(int id, String name, AssociationRole role) {
        this.id = id;
        this.name = name;
        this.role = role;
    }

    public AssociationUser() {
        super();
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public AssociationRole getRole() {
        return role;
    }

    public void setRole(AssociationRole role) {
        this.role = role;
    }

    @Override
    public String toString() {
        return "AssociationUser{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", role=" + role +
                '}';
    }
}

然后,创建一个接口 AssociationUserMap ,声明获取指定用户信息的方法。同时,创建映射文件 AssociationUserMap.xml 实现接口方法

// 接口 AssociationUserMap
package cn.edu.MyBatisDemo.mapper;

import cn.edu.MyBatisDemo.model.AssociationUser;

public interface AssociationUserMap {
    public AssociationUser selectUserById(int id); // 获取指定用户的信息
}
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "https://mybatis.org/dtd/mybatis-3-mapper.dtd">

<!-- 映射文件 AssociationUserMap.xml -->
<mapper namespace="cn.edu.MyBatisDemo.mapper.AssociationUserMap">
    <select id="selectUserById" resultMap="associationUser">
        SELECT user.id,user.name,user.role_id,role.role
            FROM association_user USER,`association_role` role
                WHERE user.role_id=role.id AND user.id=#{id}
    </select>

    <!-- id 设置别名;type 指定类 -->
    <resultMap id="associationUser" type="cn.edu.MyBatisDemo.model.AssociationUser" >
        <!-- 字段名对应的属性名 -->
        <id column="id" property="id" />
        <result column="name" property="name" />

        <!-- 映射关联对象的属性 -->
        <result column="role_id" property="role.id" />
        <result column="role" property="role.role" />
    </resultMap>
</mapper>

最后,测试结果

package cn.edu.MyBatisDemo.test;

import cn.edu.MyBatisDemo.mapper.AssociationUserMap;
import cn.edu.MyBatisDemo.model.AssociationUser;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;
import java.io.IOException;
import java.io.InputStream;

public class AssociationTest {
    @Test
    public void test() throws IOException {
        //1.根据配置文件创建数据库连接会话的工厂类
        InputStream inputStream = Resources.getResourceAsStream("mybatis.xml");
        //获取工厂类
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

        //2.通过工厂类获取数据库连接的会话
        SqlSession sqlSession = sqlSessionFactory.openSession();

        //3.通过 sqlSession 操作数据库
        try {
            AssociationUserMap userMap = sqlSession.getMapper(AssociationUserMap.class);
            //获取所有用户
            AssociationUser user = userMap.selectUserById(20230829);
            System.out.println(user);
            sqlSession.commit();
        } finally {
            sqlSession.close();
        }
    }
}

结果如图:
在这里插入图片描述

懒加载

懒加载( Lazy Loading ),是在使用所需数据时才进行加载,而不是直接加载所有关联数据。这有利于提高查询性能和减少资源消耗。当一个实体类中包含关联对象(如一对多、多对多关系)时,使用懒加载可以避免在查询主对象时立即加载所有关联对象的数据,而是等到真正需要访问关联对象时才进行加载。

简单示例:
在上面案例的基础上,先通过使用 association 标签实现分步关联查询,再进行配置懒加载

首先,再创建一个接口 AssociationRoleMap ,声明获取指定用户信息的方法。同时,创建映射文件 AssociationRoleMap.xml 实现接口方法

package cn.edu.MyBatisDemo.mapper;

import cn.edu.MyBatisDemo.model.AssociationRole;

public interface AssociationRoleMap {
    public AssociationRole selectRoleById(int id); // 获取指定用户的信息
}
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "https://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="cn.edu.MyBatisDemo.mapper.AssociationRoleMap">
    <select id="selectRoleById" resultType="associationRole">
        SELECT `id`,`role` FROM `association_role` WHERE `id`=#{id}
    </select>
</mapper>

接着,在映射文件 AssociationUserMap.xml 中,使用 association 标签实现关联查询。同时,修改 select 标签上的 SQL 语句

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "https://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="cn.edu.MyBatisDemo.mapper.AssociationUserMap">
    <select id="selectUserById" resultMap="associationUser">
    	<!-- 对比:分步关联查询的 SQL 语句相对简单些 -->
        SELECT `id`,`name`,`role_id` FROM `association_user` WHERE `id`=#{id}
    </select>

    <!-- id 设置别名;type 指定类 -->
    <resultMap id="associationUser" type="cn.edu.MyBatisDemo.model.AssociationUser" >
        <!-- 字段名对应的属性名 -->
        <id column="id" property="id" />
        <result column="name" property="name" />

        <!-- 映射关联对象的属性 -->
        <!-- <result column="role_id" property="role.id" /> -->
        <!-- <result column="role" property="role.role" /> -->

        <!-- 也可以使用子标签 association 实现关联查询 -->
        <!-- property = 添加 AssociationRole 属性 role ;select = 关联对象映射文件中的方法 id ;column = 外键 -->
        <association property="role" select="cn.edu.MyBatisDemo.mapper.AssociationRoleMap.selectRoleById" column="role_id" ></association>
    </resultMap>
</mapper>

然后,在 pom.xml 配置文件中添加依赖包。同时,在 resources 目录下创建 log4j.properties 资源文件。目的是生成日志文件,方便观察理解

<!-- https://mvnrepository.com/artifact/log4j/log4j -->
<dependency>
  <groupId>log4j</groupId>
  <artifactId>log4j</artifactId>
  <version>1.2.16</version>
</dependency>
#日志级别,分为八个级别( Off-关闭日志记录 > Fatal-严重错误 > Error-错误 > Warn-警告 > Info-运行信息 > Debug-调试 > Trace-低级信息 > All-所有日志记录)
#日志级别越高,过滤的信息越多

#配置根节点
log4j.rootLogger=Debug,stdout,D
#配置控制台输出
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.Threshold=Error
##输出格式(%d %p [%1] %m %n——日期时间 类 路径 信息 换行)
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %p [%l] %m %n

#配置文件输出
log4j.appender.D=org.apache.log4j.DailyRollingFileAppender
log4j.appender.D.Append=true
log4j.appender.D.File=./log4j.log
log4j.appender.D.Threshold=Debug
#输出格式
log4j.appender.D.layout=org.apache.log4j.PatternLayout
log4j.appender.D.layout.ConversionPattern=%d %p [%l] %m %n

随之,在 resources 目录下的 mybatis.xml 全局配置文件中进行配置懒加载

<!-- 懒加载配置 -->
<settings>
    <setting name="LazyLoadingEnabled" value="true"/>
    <setting name="aggressiveLazyLoading" value="false"/>
</settings>

最后,测试结果
1.只获取 association_user 中的 name 属性(只加载所需要的数据,其他数据不加载)
在这里插入图片描述
查看日志,结果如图:
在这里插入图片描述

2.分步关联查询(加载所有关联数据)
在这里插入图片描述
查看日志,结果如图:
在这里插入图片描述

对象为集合时的关联查询

当关联查询的对象为集合时,与上面案例的主要区别为使用的是 collection 标签,而不是 association 标签。

简单示例:
首先,在实体类 AssociationRole 中添加 users 属性
在这里插入图片描述

接着,分别在接口 AssociationUserMap 和 AssociationRoleMap 中添加相应的方法
在这里插入图片描述
在这里插入图片描述

然后,分别在映射文件 AssociationUserMap.xml 和 AssociationRoleMap.xml 中实现相应的方法。同时在 AssociationRoleMap.xml 配置关联映射
在这里插入图片描述
在这里插入图片描述

最后,测试结果
结果如图:
在这里插入图片描述

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

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

相关文章

win11,引导项管理

1&#xff0c;打开cmd,输入msconfig 2,进入引导选项卡 3&#xff0c;删除不需要的引导项

Go语言常用命令详解(三)

文章目录 前言常用命令go get示例参数说明 go install示例参数说明 go list示例 go mod示例参数说明 go work基本用法示例 go tool示例 go version示例 go vet示例 总结写在最后 前言 接着上一篇继续介绍Go语言的常用命令 常用命令 以下是一些常用的Go命令&#xff0c;这些命…

支付宝生僻字选择器

本文的数据来源于支付宝网页版本生僻字选择器。 let rareWords[{spell: "a",words: ["奡", "靉", "叆"]}, {spell: "b",words: ["仌", "昺", "竝", "霦", "犇", "愊…

mysql底层是如何存放数据的

总览 首先总的来说&#xff0c;分为四个层级&#xff0c;行页区段。行就是数据库里的一行数据。 但一次从磁盘读进内存的数据量是一页&#xff08;页是读写的单位&#xff0c;默认16KB一页&#xff09;&#xff0c;页分很多种类&#xff0c;例如数据页、溢出页、undo日志页。 …

Rust语言精讲:数据类型全解析

大家好&#xff01;我是lincyang。 今天&#xff0c;我们将深入探讨Rust语言中的数据类型&#xff0c;这是理解和掌握Rust的基础。 Rust语言数据类型概览 Rust是静态类型语言&#xff0c;所有变量类型在编译时确定。Rust的数据类型分为两类&#xff1a;标量类型和复合类型。…

909-2014-T3

文章目录 1.原题2.算法思想3.关键代码4.完整代码5.运行结果 1.原题 有n个顶点的无向图&#xff0c;使用邻接矩阵作为存储结构。为减少存储空间&#xff0c;使用数组按照行主映射方式仅保存下三角矩阵。请给出映射公式&#xff0c;并编写算法计算给定顶点的度。叙述算法思想并用…

基于ubuntu20.04安装ros系统搭配使用工业相机

基于ubuntu20.04安装ros系统搭配使用工业相机 1. ROS系统安装部署1.1更新镜像源1.1.1 备份源文件1.1.2 更新阿里源1.1.3 更新软件源 1.2 ros系统安装1.2.1 添加ros软件源1.2.2 添加秘钥1.2.3 更新软件源1.2.4 配置及更换最佳软件源1.2.5 ROS安装1.2.6 初始化rosdep1.2.7 设置环…

【Hello Go】Go语言文本文件处理

文本文件处理 字符串处理字符串操作ContainsJoinindexrepeatReplaceSplitTrimFields 字符串转换AppendFormatParse 正则表达式Json处理编码Json通过结构体生产Json通过map生产json 解码Json解析到结构体解析到interface 文件操作相关api介绍建立和打开文件关闭文件写文件读文件…

基于Apache部署虚拟主机网站

文章目录 Apache释义Apache配置关闭防火墙和selinux 更改默认页内容更改默认页存放位置个人用户主页功能基于口令登录网站虚拟主机功能基于ip地址相同ip不同域名相同ip不同端口 学习本章完成目标 1.httpd服务程序的基本部署。 2.个人用户主页功能和口令加密认证方式的实现。 3.…

Linux02 VIM编辑器

Linux02 VIM编辑器 基本上 vi/vim 共分为三种模式&#xff0c; 分别是命令模式&#xff08;Command mode&#xff09;&#xff0c;输入模式&#xff08;Insert mode&#xff09;和底线命令模式&#xff08;Last line mode&#xff09;。 三种状态进行切换 插入模式&#xff1a…

【机器学习】039_合理初始化

一、稳定训练 目标&#xff1a;使梯度值在更合理的范围内 常见方法如下&#xff1a; 将乘法变为加法 ResNet&#xff1a;当层数较多时&#xff0c;会加入一些加法进去 LSTM&#xff1a;如果时序序列较长时&#xff0c;把一些对时序的乘法做加法 归一化 梯度归一化&…

Java(五)(Object类,克隆,Objects类,包装类,StringBuilder,StringJoiner,BigDecimal)

目录 Object类 Object类的常见方法: 克隆 浅克隆 深克隆 Objects类 包装类 StringBuilder StringJoiner BigDecimal Object类 Object类是java中的祖宗类,因此,Java中所有的类的对象都可以直接使用object类提供的一些方法 Object类的常见方法: public String toStrin…

Redis-Redis持久化,主从哨兵架构详解

Redis持久化 RDB快照&#xff08;snapshot&#xff09; 在默认情况下&#xff0c; Redis 将内存数据库快照保存在名字为 dump.rdb 的二进制文件中。 你可以对 Redis 进行设置&#xff0c; 让它在“ N 秒内数据集至少有 M 个改动”这一条件被满足时&#xff0c; 自动保存一次数…

Mac- Iterm 2 (替换mac terminal 终端的下一代终端工具)

1.应用场景 主要用于macOS中作为终端工具使用, 执行终端命令, Iterm 2 (替换mac terminal 终端的下一代终端工具) 2.学习/操作 1.文档阅读 chatgpt & 其他资料 2.整理输出 2.1 是什么 Iterm 2 (替换mac terminal 终端的下一代终端工具) 2.2 为什么需要「应用场景」 macOS…

自定义类型之结构体

&#x1d649;&#x1d65e;&#x1d658;&#x1d65a;!!&#x1f44f;&#x1f3fb;‧✧̣̥̇‧✦&#x1f44f;&#x1f3fb;‧✧̣̥̇‧✦ &#x1f44f;&#x1f3fb;‧✧̣̥̇:Solitary-walk ⸝⋆ ━━━┓ - 个性标签 - &#xff1a;来于“云”的“羽球人”。…

操作系统 应用题 例题+参考答案(考研真题)

1.&#xff08;考研真题&#xff09;一个多道批处理系统中仅有P1和P2两个作业&#xff0c;P2比P1晚5ms到达&#xff0c;它们的计算和I/O操作顺序如下。 P1&#xff1a;计算60ms&#xff0c;I/O 80ms&#xff0c;计算20ms。 P2&#xff1a;计算120ms&#xff0c;I/O 40ms&…

会声会影2024出来了吗?会声会影2023怎么使用?

会声会影20247中文旗舰版 Corel VideoStudio 是一款功能强大的视频编辑软件&#xff0c;可以帮助用户创建高质量的视频作品。它提供了一系列完善的编辑功能&#xff0c;包括视频编辑、音频编辑、调色、特效、字幕、标题等。它还支持多种视频格式&#xff0c;可以将视频转换为多…

算法通关村第十二关-青铜挑战字符串

大家好我是苏麟 , 今天带来字符串专题 . 转换成小写字母 描述 : 给你一个字符串 s &#xff0c;将该字符串中的大写字母转换成相同的小写字母&#xff0c;返回新的字符串。 题目 : LeetCode 709.转换成小写字母 : 709. 转换成小写字母 分析 : 这个题可以先遍历整个字符串…

django+drf+vue 简单系统搭建 (4) 用户权限

权限控制是web中的重要组成部分。与以往的博客系统不同&#xff0c;本次工具页面仅支持注册用户。 每个注册用户都能访问到工具页面&#xff0c;并且提交自己的task来选择具体的工具来处理自己提交的文件。每个注册用户都只能访问到自己提交的task&#xff0c;而管理员则可以查…

uni-app:实现request请求的递归(设置request请求的访问次数),并且调用自定义方法给出返回值

一、效果展示 失败效果 成功效果 二、写入后端请求部分 分析 ①自定义一个模块common.js主要用于封装所有的请求函数 ②核心代码 function requestWithRetry(cmd, username, password, retryCount) {return new Promise((resolve, reject) > {uni.request({url: ip sys…