Mybatis(7)其他查询操作(多表查询)
文章目录
- Mybatis(7)其他查询操作(多表查询)
- [1. 多表查询](#1. 多表查询)
- [2. 总结:](#2. 总结:)
观前提醒:
如果你是第一次点击这篇博客,需要你回看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类),对应一张表的查询。
但是,还是要知道,多表查询,是怎么写的,面试会考。
最后,如果这篇博客能帮到你的,请你点点赞,有写错了,写的不好的,欢迎评论指出,谢谢!