JavaEE简单实例——MyBatis的一对一映射的嵌套查询的简单介绍和基础配置

news2025/7/20 18:29:34

简单介绍:

在前一章我们介绍了关于MyBatis的多表查询的时候的对应关系,其中有三种对应关系,分别是一对一,一对多,多对多的关系。如果忘记了这三种方式的对应形式可以去前面看看,一定要记住这三种映射关系的图表形式,以及在Java中的以类的形式存在的嵌套关系。这次我们来详细的讲解一对一关系的详细使用方法。

在一对一映射关系的查询中,需要使用到<assciaition>元素,它提供了一系列的用于维护表与表之间关系的属性:

property:用于指定映射关系到实体类对象的属性,与表字段一一对应

column:用于指定表中与对象的属性对应的字段。使用column和property可以完成数据表字段和实体类属性的映射关系。

javaType:用于指定映射到实体类属性值的数据类型

jdbcType:用于指定数据表中对应字段的类型

fetchType:用于指定在关联查询时是否启动延迟加载,fatchType有属性有两个值,lazy和eager两个属性值,默认为lazy。

select:用于指定引入嵌套查询的子SQL语句。

typeHandler:用于指定一个类处理器

<assciaition>是resultMap的子元素,也就是说要使用这个元素需要手动的指定自定义映射规则,并且在我们做多表查询的时候有两种配置方法,嵌套查询和嵌套结果集,我们先讲解嵌套查询

嵌套查询的方式进行多表查询:

嵌套查询的核心理念:将一条查询语句的结果当作另一条查询语句的查询条件。比如在我们想要查询学生的学生卡的时候,需要首先查询学生的信息,得到这个学生的所有信息之后找出学籍号这一列,然后用这个数据再去查询学生卡,在SQL语句中就是这样的:

查询结果就是这样的:

而我们要做就是将子查询的查询结果分离出我们要的列的信息之后,再把这个信息传递给父查询作为查询参数进行进一步查询,最终得出我们想要的结果 

前期准备:

首先我们需要两个数据库,一个用来存储学生的相关信息,一个用来存储学生卡的相关信息:

SQL语句:

show databases ;
use mybatis;
show tables ;
create table user(
    id int COMMENT 'id信息',
    name varchar(10) COMMENT '姓名',
    sex varbinary(3) COMMENT '性别',
    id_card int COMMENT 'id号码'
);
# 这两张表使用id_card字段形成一对一的关系
insert into user values (1,'张三','男',1),
                        (2,'李四','女',2),
                        (3,'王五','男',3);
create table id_card(
    id_card int COMMENT 'id号码',
    Information varchar(30) COMMENT '信息'
);
insert into id_card values (1,'我是张三的信息'),
                           (2,'我是李四的信息'),
                           (3,'我是王五的信息');
select * from user;
select * from id_card;

 然后就是与之对应的Java实体类,我们需要两个类,一个学生类用来存储学生的相关信息,一个学生卡类用来存储学生的相关信息:

首先是学生卡类:

package com.mybatis.POJO;

public class IdCard {
    private int id_card;
    private String Information;

    public IdCard() {
    }

    public IdCard(int id_card, String information) {
        this.id_card = id_card;
        Information = information;
    }

    public int getId_card() {
        return id_card;
    }

    public void setId_card(int id_card) {
        this.id_card = id_card;
    }

    public String getInformation() {
        return Information;
    }

    public void setInformation(String information) {
        Information = information;
    }

    @Override
    public String toString() {
        return "IdCard{" +
                "id_card=" + id_card +
                ", Information='" + Information + '\'' +
                '}';
    }
}

然后是学生类:

package com.mybatis.POJO;

public class User{
    private int id;
    private String name;
    private String sex;
    private IdCard id_card;

    public User() {
    }

    public User(int id, String name, String sex, IdCard id_card) {
        this.id = id;
        this.name = name;
        this.sex = sex;
        this.id_card = id_card;
    }

    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 String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public IdCard getId_card() {
        return id_card;
    }

    public void setId_card(IdCard id_card) {
        this.id_card = id_card;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", sex='" + sex + '\'' +
                ", id_card=" + id_card +
                '}';
    }
}

 在创建学生类的时候就需要注意了,在我们之前介绍一对一查询的Java类实现的时候曾经说过,在Java中体现一对一的查询就是在本类中定义与之关联的类的对象做为属性。比如在A类中定义B类对象作为属性,在B类中定义A类为属性。形成一种互相包含的属性

 关键点在这里:

在学生类里面有一个属性,它的类型是学生卡类,也就是达成了我们之前说过一个类里面包含与之关联的对象作为属性,这里是第一个需要注意的点。 

使用方法:

在我们创建完之前的数据库和实体类之后,接下来就是进行我们SQL映射语句的编写了:

在我们的嵌套查询的形式中,需要将子查询和父查询分开来写,也就是需要两条SQL映射语句:

<!--    首先是子查询-->
    <select id="selectIdCard" parameterType="int" resultType="IdCard">
        select * from id_card where id_card = #{id};
    </select>
<!--    然后是父查询-->
    <select id="selectUser" resultMap="MapperIdCard" parameterType="int">
        select * from user where id = #{id};
    </select>
    <resultMap id="MapperIdCard" type="User">
        <result column="name" property="name"/>
        <result column="id" property="id"/>
        <result column="sex" property="sex"/>
        <association property="id_card"
                     column="id_card"
                     javaType="IdCard"
                     select="mappers.NestedSelect.selectIdCard"/>
    </resultMap>

我们来解释一下上面的SQL映射文件的片段:

最上面的SQL映射语句是子查询,也就是对应了我们完整的SQL语句中的这个位置:

 传递的参数就是int类型,就是要根据这个值查询,返回的类型是IdCard也就是是这个值:

子查询就是由这些组成的,然后关键在于夫查询:

父查询的SQL语句对应完整的SQL语句如下:

SQL语句的传入参数的属性是int类型,也就是要根据这个值去查询学生信息,然后从学生信息中获取到学生卡号信息,再用学生卡号信息去查询学生卡信息,具体的参数的流向如下图所示:

 红色的箭头指向的是参数的传递,蓝色的箭头指向的是结果集的封装。那么最后的SQL语句运行结果就是这样的:

 其中由两个比较重要的问题,是我们在之后编写自定义映射规则的时候需要解决的:

1.如何从所有的参数中单独拿出id_card列的数据进行传递?

2.如何将结果集封装成IdCard属性并传递给学生类?

然后我们就要开始对我们之前编写的SQL映射文件中的内容进行详细的解释:

<?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">
<!--        接口式开发有两个规范: -->
<!--1.接口中方法的名称必须与SQL语句的唯一标识,也就是id的值保持一致,resultType就是接口中返回值的类型,parameterType就是接口中方法的参数的类型-->
<!-- 2.mapper标签的namespace属性必须是接口的全路径,否则在运行的时候会无法找到接口对象的SQL映射文件 -->
<mapper namespace="mappers.NestedSelect">
    <!--    根据id查询单条数据-->
    <select id="selectOne" resultType="User" parameterType="int">
        select *
        from user
        where id = #{id};
    </select>
    <!--    查询所有的数据-->
    <select id="selectAll" resultType="User">
        select *
        from user;
    </select>
<!--    开始编写关于嵌套查询的内容-->
<!--    首先是子查询-->
    <select id="selectIdCard" parameterType="int" resultType="IdCard">
        select * from id_card where id_card = #{id};
    </select>
<!--    然后是父查询-->
    <select id="selectUser" resultMap="MapperIdCard" parameterType="int">
        select * from user where id = #{id};
    </select>
    <resultMap id="MapperIdCard" type="User">
        <result column="name" property="name"/>
        <result column="id" property="id"/>
        <result column="sex" property="sex"/>
        <association property="id_card"
                     column="id_card"
                     javaType="IdCard"
                     select="mappers.NestedSelect.selectIdCard"/>
    </resultMap>
</mapper>

 首先我们来看父查询中的resultMap部分:

其中在我们的自定义结果集映射的部分,前几个部分都是和之前是一样的,在最后的<association>元素中,property指向的就是我们的一个类里面包含与之关联的对象作为属性,column就是与其他表建立联系的字段,这个值也就是我们传递给子查询的参数的来源,JavaType的值就是一个类里面包含与之关联的对象作为属性的这个与之关联的对象的类,也就是我们的IdCard的类名,最后的select指向的就是子查询的SQL语句的唯一标识:

具体的参数的传递如下面的图式所示:

最终的运行结果就是如下所示:

 在数据库中的查询语句如下:

查询结果如下:

代码实现:

最后总结一下完整的代码:

SQL映射文件:

<?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">
<!--        接口式开发有两个规范: -->
<!--1.接口中方法的名称必须与SQL语句的唯一标识,也就是id的值保持一致,resultType就是接口中返回值的类型,parameterType就是接口中方法的参数的类型-->
<!-- 2.mapper标签的namespace属性必须是接口的全路径,否则在运行的时候会无法找到接口对象的SQL映射文件 -->
<mapper namespace="mappers.NestedSelect">
    <!--    根据id查询单条数据-->
    <select id="selectOne" resultType="User" parameterType="int">
        select *
        from user
        where id = #{id};
    </select>
    <!--    查询所有的数据-->
    <select id="selectAll" resultType="User">
        select *
        from user;
    </select>
<!--    开始编写关于嵌套查询的内容-->
<!--    首先是子查询-->
    <select id="selectIdCard" parameterType="int" resultType="IdCard">
        select * from id_card where id_card = #{id};
    </select>
<!--    然后是父查询-->
    <select id="selectUser" resultMap="MapperIdCard" parameterType="int">
        select * from user where id = #{id};
    </select>
    <resultMap id="MapperIdCard" type="User">
        <result column="name" property="name"/>
        <result column="id" property="id"/>
        <result column="sex" property="sex"/>
        <association property="id_card"
                     column="id_card"
                     javaType="IdCard"
                     select="mappers.NestedSelect.selectIdCard"/>
    </resultMap>
</mapper>

接口文件:

package mappers;

import com.mybatis.POJO.IdCard;
import com.mybatis.POJO.User;

import java.util.List;

public interface NestedSelect {
    public User selectOne(int i);
    public List<User> selectAll();
    public List<User> selectUser(int i);
    public List<IdCard> selectIdCard(int i);
}

测试类:

package mappers;

import Tools.create;
import com.mybatis.POJO.IdCard;
import com.mybatis.POJO.User;
import org.apache.ibatis.session.SqlSession;
import org.junit.Before;
import org.junit.Test;

public class NestedSelectTest {
    NestedSelect mapper = null;
    SqlSession session = null;

    @Before
    public void setUp() throws Exception {
        session = create.createSqlSession();
        mapper = create.createNestedSelectMappers();
    }
    @Test
    public void testSelectOne() {
        User user = mapper.selectOne(1);
        System.out.println(user.toString());
    }

    @Test
    public void testSelectAll() {
        for (User user : mapper.selectAll()) {
            System.out.println(user.toString());
        }
    }
//    测试嵌套查询的运行语句
    @Test
    public void selectUser(){
        for (User user : mapper.selectUser(2)) {
            System.out.println(user.toString());
        }
    }
    @Test
    public void selectIdCard(){
        for (IdCard idCard : mapper.selectIdCard(1)) {
            System.out.println(idCard.toString());
        }
    }
}

运行结果:

注意点: 

在这一章节中所需要的注意点就是我们在配置SQL映射文件的时候一定要清晰的理解这些配置项之间的嵌套关系,以及类与类,表与表之间的关系,或者如果不理解的话,至少知道怎么写能出现什么效果。常见的报错就是SQL语句的嵌套关系错误导致的查询结果不正确,如果出现了查询结果不正确,首先去检查映射关系的部分。如果出现了查询不到数据,可以去看看有没有配置之前的驼峰映射,这个配置会影响后续的我们的自定义映射关系的数据,有可能会导致最终的结果查询不到数据。

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

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

相关文章

微服务架构下路由、多活、灰度、限流的探索与挑战

导语 2022腾讯全球数字生态大会已圆满落幕&#xff0c;大会以“数实创新、产业共进”为主题&#xff0c;聚焦数实融合&#xff0c;探索以全真互联的数字技术助力实体经济高质量发展。大会设有29个产品技术主题专场、18个行业主题专场和6个生态主题专场&#xff0c;各业务负责人…

Linux基础命令-locate快速查找文件

文章​​​​​​​目录 locate 命令介绍 语法格式 基本参数 参考实例 1&#xff09;查找1.txt相关的文件 2&#xff09;查找包含pass和txt都有的文件 3&#xff09;只匹配文件名&#xff0c;有路径的情况下不进行匹配 4&#xff09;匹配不区分大小写的文件 5&#…

Java多线程(四)---并发编程容器

1.经常使用什么并发容器&#xff0c;为什么&#xff1f;答&#xff1a;Vector、ConcurrentHashMap、HasTable一般软件开发中容器用的最多的就是HashMap、ArrayList&#xff0c;LinkedList &#xff0c;等等但是在多线程开发中就不能乱用容器&#xff0c;如果使用了未加锁&#…

Java EE|TCP/IP协议栈之TCP协议工作机制上

文章目录前言一、确认应答二、超时重传三、连接管理三次握手四次挥手前言 前边&#xff0c;我们已经大概交代了TCP的报文结构。但是仍有一些字段我们不确定到底怎么理解&#xff0c;这里就分析TCP的内部工作机制了。 TCP的内部很复杂&#xff0c;有很多机制&#xff0c;这里我们…

Super intelligent port AI smart port termial, CIMCAI top port AI

中国上海人工智能企业CIMCAI&#xff0c;全球港航人工智能领军者企业&#xff0c;顶尖AI科技及工业级成熟人工智能产品&#xff0c;打造高效能智能化港口数字化航运码头数字化。Ceaspectus™领跑全球港口人工智能&#xff0c;建设新一代高效能先进港口码头。Ceaspectus™先进方…

通过操作Cortex-A7核,串口输入相应的命令,控制LED灯进行工作

1.通过操作Cortex-A7核&#xff0c;串口输入相应的命令&#xff0c;控制LED灯进行工作 例如在串口输入led1on,开饭led1灯点亮 2.例如在串口输入led1off,开饭led1灯熄灭 3.例如在串口输入led2on,开饭led2灯点亮 4.例如在串口输入led2off,开饭led2灯熄灭 5.例如在串口输入led…

苹果电容笔和普通电容笔区别是什么?开学好用电容笔推荐

苹果的电容笔与一般的电容笔有何不同呢&#xff1f;两者的差距并不是很大。不过这款原装的苹果电容笔&#xff0c;重量要普通的电容笔重得多&#xff0c;而且笔尖还有一个特殊的重力感应装置&#xff0c;在其他方面两者并没有太大的差异。但是&#xff0c;由于苹果电容笔的售价…

QT自绘标题和边框

在QT中如果想要自绘标题和边框&#xff0c;一般步骤是&#xff1a; 1&#xff09; 在创建窗口前设置Qt::FramelessWindowHint标志&#xff0c;设置该标志后会创建一个无标题、无边框的窗口。 2&#xff09;在客户区域的顶部创建一个自绘标题栏。 3&#xff09;给窗口绘制一个背…

Hadoop的生成经验调优和基准测试

文章目录&#xff08;1&#xff09;项目经验之HDFS存储多目录&#xff08;2&#xff09;项目经验之集群数据均衡&#xff08;3&#xff09;项目经验之Hadoop参数调优&#xff08;4&#xff09;项目经验之支持LZO压缩配置&#xff08;5&#xff09;项目经验之LZO创建索引&#x…

软考中级--嵌入式系统设计师考试培训教程开始了

1.考试时间: 1.1 上半年5月下旬考试 1.2 下半年11月上旬考试 2.考试内容 2.1 系统基础 满分75分 时间150分钟 2.2 系统设计 满分75分 时间150分钟 3.计划安排 3.1 熟悉考试大纲 3.2 按考纲学习相关内容 整理设计知识 快速学习形成知识印象 3.3 复习整理的知识 …

Hadoop3.3.1完全分布式部署

Hadoop目录Hadoop3.3.1完全分布式部署(一)1、HDFS一、安装1、基础安装1.1、配置JDK-181.2、下载并解压hadoop安装包本地运行模式测试 eg:2、完全分布式运行模式1、概要&#xff1a;2、编写集群分发脚本&#xff0c;把1~4步安装的同步到其他服务器&#xff1a;2.1、创建脚本vim …

Tailwind CSS 在Vue中的使用

什么是Tailwind CSS&#xff1f; Tailwind CSS 是一个功能类优先的 CSS 框架&#xff0c;它集成了诸如 flex, pt-4, text-center 和 rotate-90 这样的的类&#xff0c;支持 hover 和 focus 样式&#xff0c;它们能直接在脚本标记语言中组合起来&#xff0c;构建出任何设计。 …

【算法基础】 Trie树

一、Trie树Trie树用于高效存储和查找字符串集合的数据结构。二、Trie字符串统计维护一个字符串集合&#xff0c;支持两种操作&#xff1a;I x 向集合中插入一个字符串 x&#xff1b;Q x 询问一个字符串在集合中出现了多少次。共有 N&#xfffd;个操作&#xff0c;所有输入的字…

c#前端实现对pcl点云颜色根据强度特征动态变化突出指定对象

前言 本文主要介绍如何使用c# winform对点云颜色根据点云强度信息对显示的点云颜色进行动态调整。 目的是根据强度信息采用不同的颜色特征突出不同的物体。 一、点云强度是什么&#xff1f; 点云强度又可以叫做反射率&#xff0c; 通常常见的点云格式包括&#xff1a;以pcl为…

SpringBoot可以同时处理多少请求?

本文已收录至我的Github仓库DayDayUP&#xff1a;github.com/RobodLee/DayDayUP&#xff0c;欢迎Star ⭐⭐⭐⭐⭐转载请注明出处&#xff1a;https://blog.csdn.net/weixin_43461520/article/details/129207427 前言 前两天面试的时候&#xff0c;面试官问我&#xff1a;一个i…

【拿好了!Linux 运维必备的 13 款实用工具!】

​本文介绍几款 Linux 运维比较实用的工具&#xff0c;希望对 Linux 运维人员有所帮助。 查看进程占用带宽情况 – Nethogs Nethogs 是一个终端下的网络流量监控工具可以直观的显示每个进程占用的带宽。 下载&#xff1a; http://sourceforge.net/projects/nethogs/files/ne…

NPDP认证|产品研发过程中,产生冲突怎么办?

随着传统行业在研发过程中牵涉到很多利益相关方,这些相关方在产品研发过程中关注角度的不同,会产生各种各样的矛盾冲突&#xff0c;如研发与产品的冲突、运营与产品的冲突、客户与产品的冲突&#xff0c;那么产生冲突的原因是什么呢&#xff1f; 产生冲突的原因&#xff1f; 1…

Redis:实现全局唯一ID

Redis&#xff1a;实现全局唯一ID一. 概述二. 实现&#xff08;1&#xff09;获取初始时间戳&#xff08;2&#xff09;生成全局ID三. 测试为什么可以实现全局唯一&#xff1f;其他唯一ID策略补充&#xff1a;countDownLatch一. 概述 全局ID生成器&#xff1a;是一种在【分布式…

墨天轮发布数据库行业报告,创邻科技Galaxybase大放异彩

近日&#xff0c;知名数据库社区墨天轮发布《2022中国数据库行业年度分析报告》&#xff0c;该报告由墨天轮联合业界专家学者共同编写&#xff0c;共122页&#xff0c;详细总结了2022年数据库行业产学研用的发展近况、挑战以及对未来趋势的展望。旨在于给数据库行业带来有价值的…

Hadoop命令大全

HDFS分布式文件系统 &#xff0c; 将一个大的文件拆分成多个小文件存储在多台服务器中 文件系统&#xff1a; 目录结构&#xff08;树状结构&#xff09; "/" 树根&#xff0c; 目录结构在namenode中维护 目录 1.查看当前目录 2.创建多级目录 3.上传文件 4.查…