Mybatis(7)其他查询操作(多表查询)

Mybatis(7)其他查询操作(多表查询)

文章目录

观前提醒:

如果你是第一次点击这篇博客,需要你回看Mybatis系列的这个博客:
Mybatis(6)XML方式:新增,删除,修改

这篇博客的代码,都是需要自己敲一下的。

建议你看着我说的知识点,自己尝试一下,创建 Springboot项目,使用 Mybatis框架,访问数据库。

这里使用的数据库是 MySQL。

图形化工具:Navicat

sql文件获取:https://gitee.com/mrbgvhbhjv/java-ee-course

1. 多表查询

多个表之间,是可以联合起来,进行查询的。

准备数据库:

sql 复制代码
DROP TABLE IF EXISTS `article_info`;
CREATE TABLE `article_info`  (
  `id` int NOT NULL AUTO_INCREMENT,
  `title` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
  `content` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
  `uid` int NOT NULL,
  `delete_flag` tinyint NULL DEFAULT 0 COMMENT '0-正常, 1-删除',
  `create_time` datetime NULL DEFAULT CURRENT_TIMESTAMP,
  `update_time` datetime NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;

-- 插入数据
INSERT INTO `article_info` VALUES (1, 'Java', 'Java正文', 1, 0, '2025-10-29 13:38:09', '2025-10-29 13:38:09');

SET FOREIGN_KEY_CHECKS = 1;

打开 Navicat,选择你用来练习 Mybatis 代码的数据库,将这段 sql语句代码,复制粘贴到新的查询中,并执行。

1.1 多表查询举例:

要求:根据 文章id,查询文章和这篇文章的作者。

sql语句:

没有美化的sql语句:

sql 复制代码
select ta.*,tb.username,tb.id from article_info as ta,user_info as tb where ta.uid = tb.id and ta.id = 1

美化之后的 sql语句:

sql 复制代码
SELECT
	ta.*,tb.username,tb.age 
FROM
	article_info AS ta,
	user_info AS tb 
WHERE
	ta.uid = tb.id 
	AND ta.id = 1

这是典型的多表查询语句。

当然,可以使用 左连接,右连接:

  • 左连接:返回左表的所有记录和右表中匹配的记录,右表中没有匹配的记录则显示为NULL。
  • 右连接:返回右表的所有记录和左表中匹配的记录,左表中没有匹配的记录则显示为NULL。

sql语句:

sql 复制代码
-- 左连接
SELECT
	* 
FROM
	article_info AS ta
	LEFT JOIN user_info AS tb ON ta.uid = tb.id 
WHERE
	ta.id = 1 
	
-- 右连接
SELECT
	* 
FROM
	article_info AS ta
	RIGHT JOIN user_info AS tb ON ta.uid = tb.id 
WHERE
	ta.id = 1

1.2 使用 Mybatis,实现多表查询(使用 xml 的方式):

进行多表查询之前,我们可以先测试 单表查询,看结果是否能够正确输出 表 的信息。

测试单表查询:

需求:查询 article表中 id 为 1 的记录。
创建类 ArticleInfo:
java 复制代码
import lombok.Data;
import java.util.Date;
@Data
public class ArticleInfo {
	private Integer id;
	private String title;
	private String content;
	private Integer uid;
	private Integer deleteFlag;
	private Date createTime;
	private Date updateTime;
}
创建接口:
java 复制代码
package org.example.mybatis_demo_20251031.mapper;


import org.apache.ibatis.annotations.Mapper;
import org.example.mybatis_demo_20251031.model.ArticleInfo;

@Mapper
public interface ArticleInfoMapper {

    ArticleInfo selectArticleById(Integer id);
}
创建 xml 文件:
java 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.example.mybatis_demo_20251031.mapper.ArticleInfoMapper">


    <select id="selectArticleById" resultType="org.example.mybatis_demo_20251031.model.ArticleInfo">
        select * from article_info where id = #{id};
    </select>

</mapper>
测试代码:
java 复制代码
package org.example.mybatis_demo_20251031.mapper;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import static org.junit.jupiter.api.Assertions.*;

@SpringBootTest
class ArticleInfoMapperTest {

    @Autowired
    private ArticleInfoMapper articleInfoMapper;

    @Test
    void selectArticleById() {
        System.out.println(articleInfoMapper.selectArticleById(1));
    }


}
运行结果:

多表查询:

多表查询,我使用 where 关联两张表 的 sql:

sql 复制代码
SELECT
	ta.*,tb.username,tb.age 
FROM
	article_info AS ta,
	user_info AS tb 
WHERE
	ta.uid = tb.id 
	AND ta.id = 1

代码:

运行结果:

日志能够显示,确实能够查到 user_info表 的信息,但是,输出的结果,是没有 user_info表 的 username,age两个字段的值的。

原因是:接口的返回值是 AtricleInfo对象,没有 UserInfo对象 ,无法接收 username,age两个字段的值。

解决办法,在 AtricleInfo类 中,添加这两个属性:

java 复制代码
package org.example.mybatis_demo_20251031.model;

import lombok.Data;
import java.util.Date;

@Data
public class ArticleInfo {
    private Integer id;
    private String title;
    private String content;
    private Integer uid;
    private Integer deleteFlag;
    private Date createTime;
    private Date updateTime;

    //UserInfo类 的两个属性,接收user_info表 的 username,age两个字段的值
    private String username;
    private Integer age;
}

其余代码不变,运行结果:

1.3 总结:

多表查询的方式,还有很多实现方式,我是使用了在返回值指定的 类(上面的 ArticleInfo) 中,添加属性,接收 字段 的值。

上述多表查询,我们进行了演示,但是,我仅仅是演示,不去深入说明的理由是:

企业中,尽量避免多表查询 ,但不是不能用!!!

原因:多表查询,数据量太大,查询数据速度慢,很影响程序的性能

更推荐使用嵌套查询(也叫子查询)。

这图转换一下,嵌套查询就是:select * from user_info where id = (select article_info.uid from article_info where id = 1)

代码思路是:调用接口1,获取 用户的id,作为接口2的参数。

这是 Service层 需要做的事情。

原因详细分析:

假设,sql1 是一个多表查询 的语句。
sql2,sql3 ,是两条单表查询的语句,两条语句结合,形成嵌套查询

sql1,需要 100ms ,才能查询到数据
sql2,sql3,分别需要 70ms ,才能查询到数据。

那么,sql2 + sql3 耗费的时间 > sql1 耗费的时间?

答:不是!!!

公司的服务器 ,不是单线程工作,而是多线程工作 的。

这是一个很简陋的图,表示公司的 mysql集群。

假设,mysql集群,有 16个线程,可以同时处理 sql语句。

那么,sql2,sql3,分别占用两个线程 ,执行完需要 70ms,sql2 + sql3 耗费的时间,不是 70 + 70,而是每条语句单独执行
sql2 + sql3 耗费的时间,总共就需要 70ms 左右

sql1 占用一个线程,耗费的时间就是 100ms

如果,每条 sql语句,都像 sql1一样,都需要这么长的时间,占满了线程,其他程序没法用了,这就不合理。

单条 sql语句,执行的速度快,线程释放的速度也就快了,不会造成拥堵

2. 总结:

多表查询,在公司,95%,都是尽量避免使用,原因我也分析了。

Dao/Mapper层中:一个mapper类(Dao类),对应一张表的查询。

但是,还是要知道,多表查询,是怎么写的,面试会考。

最后,如果这篇博客能帮到你的,请你点点赞,有写错了,写的不好的,欢迎评论指出,谢谢!

下一篇博客:Mybatis(8)#{}和${}的区别,排序,模糊查询

相关推荐
毕设源码-郭学长1 小时前
【开题答辩全过程】以 基于Springboot图书管理系统为例,包含答辩的问题和答案
java·spring boot·后端
毕设源码-钟学长2 小时前
【开题答辩全过程】以 基于springboot网络游戏账号租赁以及出售系统为例,包含答辩的问题和答案
java·spring boot·后端
vx+_bysj68692 小时前
【免费领源码】基于Springboot白隼校园音乐点歌系统 计算机毕业设计项目推荐上万套实战教程JAVA,node.js,C++、python、大屏数据可视化
java·spring boot·mysql·课程设计
jay神2 小时前
基于SpringBoot的英语自主学习系统
java·spring boot·后端·学习·毕业设计
dfyx9993 小时前
SpringBoot教程(三十二) SpringBoot集成Skywalking链路跟踪
spring boot·后端·skywalking
九转苍翎3 小时前
微服务学习笔记(1)——SpringColud概述
spring boot·maven·springcloud
墨染青竹梦悠然4 小时前
基于SpringBoot + vue的农产品销售系统(华夏鲜仓)
vue.js·spring boot·python·django·毕业设计·毕设
消失的旧时光-19434 小时前
第二十一课:系统是怎么一步步拆坏的?——单体到模块化实践(完整工程版)
java·spring boot·后端·架构
NGC_66114 小时前
Mybatis处理流程
数据库·oracle·mybatis