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

news/2024/4/19 18:37:47/文章来源:https://blog.csdn.net/hssjsh/article/details/129192012

简单介绍:

在前一章我们介绍了关于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;}@Overridepublic 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;}@Overridepublic 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 mapperPUBLIC "-//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 userwhere 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 mapperPUBLIC "-//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 userwhere 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;@Beforepublic void setUp() throws Exception {session = create.createSqlSession();mapper = create.createNestedSelectMappers();}@Testpublic void testSelectOne() {User user = mapper.selectOne(1);System.out.println(user.toString());}@Testpublic void testSelectAll() {for (User user : mapper.selectAll()) {System.out.println(user.toString());}}
//    测试嵌套查询的运行语句@Testpublic void selectUser(){for (User user : mapper.selectUser(2)) {System.out.println(user.toString());}}@Testpublic void selectIdCard(){for (IdCard idCard : mapper.selectIdCard(1)) {System.out.println(idCard.toString());}}
}

运行结果:

注意点: 

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

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

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

项目重构,从零开始搭建一套新的后台管理系统

背景 应公司发展需求&#xff0c;我决定重构公司的后台管理系统&#xff0c;从提出需求建议到现在的实施&#xff0c;期间花了将近半个月的时间&#xff0c;决定把这些都记录下来。 之前的后台管理系统实在是为了实现功能而实现的&#xff0c;没有考虑到后期的扩展性&#xf…

逆风翻盘拿下感知实习offer,机会总是留给有准备的人

个人背景211本&#xff0c;985硕&#xff0c;本科是计算机科学与技术专业&#xff0c;研究生是自学计算机视觉方向&#xff0c;本科主要做C和python程序设计开发&#xff0c;java安卓开发&#xff0c;研究生主要做目标检测&#xff0c;现在在入门目标跟踪和3d目标检测。无论文&…

并发编程学习篇从0-1合集

一、synchronized 一、原子性、有序性、可见性 1.1 原子性 数据库的事务&#xff1a;ACID A&#xff1a;原子性-事务是一个最小的执行的单位&#xff0c;一次事务的多次操作要么都成功&#xff0c;要么都失败。 并发编程的原子性&#xff1a;一个或多个指令在CPU执行过程中…

用Python获取弹幕的两种方式(一种简单但量少,另一量大管饱)

前言 弹幕可以给观众一种“实时互动”的错觉&#xff0c;虽然不同弹幕的发送时间有所区别&#xff0c;但是其只会在视频中特定的一个时间点出现&#xff0c;因此在相同时刻发送的弹幕基本上也具有相同的主题&#xff0c;在参与评论时就会有与其他观众同时评论的错觉。 在国内…

怎么从零开始学黑客,黑客零基础怎么自学

很多朋友对成为黑客很感兴趣&#xff0c;很大原因是因为看到电影中黑客的情节觉的特别的酷&#xff0c;看到他们动动手指就能进入任何系统&#xff0c;还有很多走上黑客之路的朋友仅仅是因为自己的qq被盗了&#xff0c;或者游戏里的装备被别人偷了&#xff0c;想要自己盗回来&a…

听车企做开发朋友说,面试Framework 必问~

近期听在车企工作的朋友说&#xff0c;今年去他们公司面试的人比往年增长了30%左右&#xff0c;但实际面试达到标准的人屈指可数&#xff0c;大多都是从 Android 开发方向转过来的。 车企招聘要求有哪些&#xff1f; 每个车企因为业务部门的不同&#xff0c;他们的要求也会有…

Linux操作系统基础知识命令参数详解

Linux操作系统 RAID分组 RAID JBOD RAID JBOD的意思是Just a Bunch Of Disks&#xff0c;是将多块硬盘串联起来组成一个大的存储设备&#xff0c;从某种意义上说这种类型不被算作RAID&#xff0c;在维基百科里JBOD同时也被归入非RAID架构。RAID JBOD将所有的磁盘串联成一个单…

保持超低温环境新方法:功耗降至十分之一!

&#xff08;图片来源&#xff1a;网络&#xff09;量子比特是量子计算机的主要构建部分&#xff0c;然而热量会导致量子比特容易出错&#xff0c;因此量子系统通常保存在超低温稀释制冷机内&#xff0c;可以将温度保持在绝对零度&#xff08;−273.15℃&#xff09;以上。但是…

如何使评论具有可操作性?取悦客户的指南

永远不要低估承认的力量。 当品牌与客户互动时&#xff0c;认可会带来更好的关系和更好的沟通。与买家和客户建立更多的个人联系意味着品牌需要证明他们支持他们的产品和客户。评论是利用客户分享他们的故事的那些时刻的绝佳机会。 为什么评论在 SaaS 中至关重要 在 B2B 软件的…

【python学习笔记】:如何去除字符串中空格

在输入数据时&#xff0c;很有可能会无意中输入多余的空格&#xff0c;或者在一些场景中&#xff0c;字符串前后不允许出现空格和特殊字符&#xff0c;此时就需要去除字符串中的空格和特殊字符。 【注意&#xff1a;这里的特殊字符&#xff0c;指的是制表符&#xff08;\t&…

ASEMI高压MOS管ASE65R330参数,ASE65R330图片

编辑-Z ASEMI高压MOS管ASE65R330参数&#xff1a; 型号&#xff1a;ASE65R330 漏极-源极电压&#xff08;VDS&#xff09;&#xff1a;650V 栅源电压&#xff08;VGS&#xff09;&#xff1a;20V 漏极电流&#xff08;ID&#xff09;&#xff1a;12.5A 功耗&#xff08;P…

57 - 深入解析任务调度

---- 整理自狄泰软件唐佐林老师课程 文章目录1. 问题1.1 思考1.2 实例分析&#xff1a;问题分析及解决2. 深入讨论2.1 任务调度的定义2.2 关于调度算法的分类2.3 什么时候进行任务调度2.4 任务的分类2.5 关于优先级调度2.6 问题2.7 调度算法的终极目标2.8 课后扩展1. 问题 系统…

在windows11上安装openssh服务端并修改端口号

在windows11上安装openssh服务端并修改端口号 目录1.软件下载地址2.修改端口3.启动ssh原文链接&#xff1a;https://blog.csdn.net/qq_62129885/article/details/1268467751.软件下载地址 Release v9.2.0.0p1-Beta PowerShell/Win32-OpenSSH (github.com) https://github.co…

浅谈智能电力运维管理系统在物业小区的应用分析

安科瑞 李亚俊 0引言 由于部分住宅小区存在电力设施纸质档案破损缺失、产权分界不清、查找故障点所在箱变&#xff08;箱式变电站&#xff0c;下同&#xff09;位置困难或小区出入口路径不明等情况&#xff0c;影响了抢修效率。为此&#xff0c;国网辽宁沈阳市沈北新区供电公…

Nacos Ignore the empty nacos configuration and get it based on dataId

1.配置错误 dataId问题 启动日志&#xff1a; 使用properties格式的文件&#xff1a; Ignore the empty nacos configuration and get it based on dataId[xxx-server] & group[DEFAULT_GROUP] Ignore the empty nacos configuration and get it based on dataId[xxx-s…

python 自动化测试 pytest 的使用

pytest 是一款以python为开发语言的第三方测试&#xff0c;主要特点如下&#xff1a; 比自带的 unittest 更简洁高效&#xff0c;兼容 unittest框架 支持参数化 可以更精确的控制要测试的测试用例 丰富的插件&#xff0c;已有300多个各种各样的插件&#xff0c;也可自定义扩…

【JDK8新特性之Stream流-Stream结果收集案例实操】

一.JDK8新特性之Stream流-Stream结果收集以及案例实操 二.Stream结果收集(collect函数)-实例实操 2.1 结果收集到集合中 /*** Stream将结果收集到集合中以及具体的实现 collect*/Testpublic void test01(){// 收集到List中 接口List<Integer> list Stream.of(1, 2, 3…

代码随想录【Day23】| 669. 修剪二叉搜索树、108. 将有序数组转换为二叉搜索树、538. 把二叉搜索树转换为累加树

669. 修剪二叉搜索树 题目链接 题目描述&#xff1a; 给定一个二叉搜索树&#xff0c;同时给定最小边界L 和最大边界 R。通过修剪二叉搜索树&#xff0c;使得所有节点的值在[L, R]中 (R>L) 。你可能需要改变树的根节点&#xff0c;所以结果应当返回修剪好的二叉搜索树的新…

Git ---- GitHub 操作

Git ---- GitHub 操作1. 创建远程仓库2. 远程仓库操作1. 创建爱你远程仓库别名2. 推送本地分支到远程仓库3. 克隆远程仓库到本地4. 邀请加入团队5. 拉取远程库内容3. 跨团队协作4. SSH 免密登录GitHub 网址&#xff1a;https://github.com/ Ps&#xff1a;全球最大同性交友网站…

makdown模版参考

这里写自定义目录标题欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题&#xff0c;有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建一个自定义列表如何创建一个注…