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)#{}和${}的区别,排序,模糊查询

相关推荐
用户8307196840821 天前
Spring Boot 集成 RabbitMQ :8 个最佳实践,杜绝消息丢失与队列阻塞
spring boot·后端·rabbitmq
Java水解1 天前
Spring Boot 视图层与模板引擎
spring boot·后端
Java水解1 天前
一文搞懂 Spring Boot 默认数据库连接池 HikariCP
spring boot·后端
洋洋技术笔记2 天前
Spring Boot Web MVC配置详解
spring boot·后端
初次攀爬者2 天前
Kafka 基础介绍
spring boot·kafka·消息队列
用户8307196840822 天前
spring ai alibaba + nacos +mcp 实现mcp服务负载均衡调用实战
spring boot·spring·mcp
Java水解2 天前
SpringBoot3全栈开发实战:从入门到精通的完整指南
spring boot·后端
初次攀爬者3 天前
RocketMQ在Spring Boot上的基础使用
java·spring boot·rocketmq
花花无缺3 天前
搞懂@Autowired 与@Resuorce
java·spring boot·后端
Derek_Smart3 天前
从一次 OOM 事故说起:打造生产级的 JVM 健康检查组件
java·jvm·spring boot