Java教程:MyBatis怎样处理一对一关联关系?分步骤介绍_对个人和身份证这种一对一关联关系,来演示mybatis的关联映射查询的使用;-程序员宅基地

技术标签: java  

在现实生活中,一对一关联关系是十分常见的。例如,一个人只能有一个身份证,同时一个身份证也只会对应一个人,它们之间的关系模型图,如图1所示。
MyBatis怎样处理一对一关联关系
图1 人与身份证的关联关系

那么使用MyBatis是怎么处理图1中的这种一对一关联关系的呢?在元素中,包含了一个子元素,MyBatis就是通过该元素来处理一对一关联关系的。

在元素中,通常可以配置以下属性:

● property:指定映射到的实体类对象属性,与表字段一一对应;

● column:指定表中对应的字段;

● javaType:指定映射到实体对象属性的类型;

● select:指定引入嵌套查询的子SQL语句,该属性用于关联映射中的嵌套查询;

● fetchType:指定在关联查询时是否启用延迟加载。fetchType属性有lazy和eager两个属性值,默认值为lazy(即默认关联映射延迟加载)。

元素的使用非常简单,只需要参考如下两种示例配置即可,具体如下:

<!--方式一:嵌套查询-->
<association property="card" column="card_id" 
javaType="com.itheima.po.IdCard"
             select="com.itheima.mapper.IdCardMapper.findCodeById" />
<!--方式二:嵌套结果-->
<association property="card" javaType="com.itheima.po.IdCard">
    <id property="id" column="card_id" />
    <result property="code" column="code" />
</association>

注意:
MyBatis在映射文件中加载关联关系对象主要通过两种方式:嵌套查询和嵌套结果。嵌套查询是指通过执行另外一条SQL映射语句来返回预期的复杂类型;嵌套结果是使用嵌套结果映射来处理重复的联合结果的子集。开发人员可以使用上述任意一种方式实现对关联关系的加载。

了解了MyBatis中处理一对一关联关系的元素和方式后,接下来就以个人和身份证之间的一对一关联关系为例,进行详细讲解。

查询个人及其关联的身份证信息是先通过查询个人表中的主键来获个人信息,然后通过表中的外键,来获取证件表中的身份证号信息。其具体实现步骤如下:

(1)创建数据表。在mybatis数据库中分别创建名为tb_idcard和tb_person的数据表,同时预先插入两条数据。其执行的SQL语句如下所示:

USE mybatis;
# 创建一个名称为tb_idcard的表
CREATE TABLE  tb_idcard( 
     id INT PRIMARY KEY AUTO_INCREMENT,
     CODE VARCHAR(18)
);
# 插入2条数据
INSERT INTO tb_idcard(CODE) VALUES('152221198711020624');
INSERT INTO tb_idcard(CODE) VALUES('152201199008150317');
# 创建一个名称为tb_person的表
CREATE TABLE  tb_person( 
     id INT PRIMARY KEY AUTO_INCREMENT,
     name VARCHAR(32),
     age INT,
     sex VARCHAR(8),
     card_id INT UNIQUE,     
     FOREIGN KEY(card_id) REFERENCES tb_idcard(id)
);
# 插入2条数据
INSERT INTO tb_person(name,age,sex,card_id) VALUES('Rose',29,'女',1);
INSERT INTO tb_person(name,age,sex,card_id) VALUES('tom',27,'男',2);

完成上述操作后,数据库tb_idcard和tb_person表中的数据如图2所示。
MyBatis怎样处理一对一关联关系
图2 tb_idcard和tb_person表

(2)在Eclipse中创建一个名为chapter09的Web项目,然后引入相关JAR包、log4j日志文件、MybatisUtils工具类以及mybatis-config.xml核心配置文件。项目环境搭建完成后的文件结构,如图3所示。
1624527322485_43.png
图3 项目文件结构

(3)在项目的com.itheima.po包下创建持久化类IdCard和Person,编辑后的代码,如文件1和文件2所示。

文件1 IdCard.java

   package com.itheima.po;
     /**
      * 证件持久化类
      */
     public class IdCard {
    
         private Integer id;
         private String code;
         public Integer getId() {
    
             return id;
         }
         public void setId(Integer id) {
    
             this.id = id;
         }
         public String getCode() {
    
             return code;
         }
         public void setCode(String code) {
    
             this.code = code;
         }
         @Override
         public String toString() {
    
             return "IdCard [id=" + id + ", code=" + code + "]";
         }
     }

文件2 Person.java

 package com.itheima.po;
 /**
  * 个人持久化类
  */
 public class Person {
    
     private Integer id;
     private String name;
     private Integer age;
     private String sex;
     private IdCard card;  //个人关联的证件
     public Integer getId() {
    
         return id;
     }
     public void setId(Integer id) {
    
         this.id = id;
     }
     public String getName() {
    
         return name;
     }
     public void setName(String name) {
    
         this.name = name;
     }
     public Integer getAge() {
    
         return age;
     }
     public void setAge(Integer age) {
    
         this.age = age;
     }
     public String getSex() {
    
         return sex;
     }
     public void setSex(String sex) {
    
         this.sex = sex;
     }
     public IdCard getCard() {
    
         return card;
     }
     public void setCard(IdCard card) {
    
         this.card = card;
     }
     @Override
     public String toString() {
    
         return "Person [id=" + id + ", name=" + name + ", "
                 + "age=" + age + ", sex=" + sex + ", card=" + card + "]";
     }
 }

在上述两个文件中,分别定义了各自的属性以及对应的getter/setter方法,同时为了方便查看输出结果还重写了toString()方法。

(4)在com.itheima.mapper包中,创建证件映射文件IdCardMapper.xml和个人映射文件PersonMapper.xml,并在两个映射文件中编写一对一关联映射查询的配置信息,如文件3和文件4所示。

文件3 IdCardMapper.xml

  <?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="com.itheima.mapper.IdCardMapper">
       <!-- 根据id查询证件信息 -->
       <select id="findCodeById" parameterType="Integer" resultType="IdCard">
           SELECT * from tb_idcard where id=#{id}
       </select>
     </mapper>

文件4 PersonMapper.xml

 <?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="com.itheima.mapper.PersonMapper">
     <!-- 嵌套查询:通过执行另外一条SQL映射语句来返回预期的特殊类型 -->
     <select id="findPersonById" parameterType="Integer" 
                                       resultMap="IdCardWithPersonResult">
         SELECT * from tb_person where id=#{id}
     </select>
     <resultMap type="Person" id="IdCardWithPersonResult">
         <id property="id" column="id" />
         <result property="name" column="name" />
         <result property="age" column="age" />
         <result property="sex" column="sex" />
         <!-- 一对一:association使用select属性引入另外一条SQL语句 -->
         <association property="card" column="card_id" javaType="IdCard"
             select="com.itheima.mapper.IdCardMapper.findCodeById" />
     </resultMap>
 </mapper>

在上述两个映射文件中,使用了MyBatis中的嵌套查询方式进行了个人及其关联的证件信息查询,因为返回的个人对象中除了基本属性外还有一个关联的card属性,所以需要手动编写结果映射。从映射文件PersonMapper.xml中可以看出,嵌套查询的方法是先执行一个简单的SQL语句,然后在进行结果映射时,将关联对象在元素中使用select属性执行另一条SQL语句(即IdCardMapper.xml中的SQL)。

(5)在核心配置文件mybatis-config.xml中,引入Mapper映射文件并定义别名,如文件5所示。

文件5 mybatis-config.xml

  <?xml version="1.0" encoding="UTF-8" ?>
     <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
         "http://mybatis.org/dtd/mybatis-3-config.dtd">
     <configuration>
         <!-- 引入数据库连接配置文件 -->
         <properties resource="db.properties" />
         <!--使用扫描包的形式定义别名 -->
         <typeAliases>
             <package name="com.itheima.po" />
         </typeAliases>
         <!--配置环境 ,默认的环境id为mysql -->
         <environments default="mysql">
             <!-- 配置id为mysql的数据库环境 -->
             <environment id="mysql">
                 <!-- 使用JDBC的事务管理 -->
                 <transactionManager type="JDBC" />
                 <!--数据库连接池 -->
                 <dataSource type="POOLED">
                     <property name="driver" value="${jdbc.driver}" />
                     <property name="url" value="${jdbc.url}" />
                     <property name="username" value="${jdbc.username}" />
                     <property name="password" value="${jdbc.password}" />
                 </dataSource>
             </environment>
         </environments>
         <!--配置Mapper的位置 -->
          <mappers>
              <mapper resource="com/itheima/mapper/IdCardMapper.xml" />
              <mapper resource="com/itheima/mapper/PersonMapper.xml" />
          </mappers>
     </configuration>

在上述核心配置文件中,首先引入了数据库连接的配置文件,然后使用扫描包的形式自定义别名,接下来进行环境的配置,最后配置了Mapper映射文件的位置信息。

(6)在com.itheima.test包中,创建测试类MybatisAssociatedTest,并在类中编写测试方法findPersonByIdTest(),如文件6所示。

文件6 MybatisAssociatedTest.java

   package com.itheima.test;
     import org.apache.ibatis.session.SqlSession;
     import org.junit.Test;
     import com.itheima.po.Person;
     import com.itheima.utils.MybatisUtils;
     /**
      * Mybatis关联查询映射测试类
      */
     public class MybatisAssociatedTest {
    
         /**
          * 嵌套查询
          */
         @Test
         public void findPersonByIdTest() {
    
             // 1、通过工具类生成SqlSession对象
             SqlSession session = MybatisUtils.getSession();
             // 2.使用MyBatis嵌套查询的方式查询id为1的人的信息
             Person person = session.selectOne("com.itheima.mapper." 
                                        + "PersonMapper.findPersonById", 1);
             // 3、输出查询结果信息
             System.out.println(person);
             // 4、关闭SqlSession
             session.close();
         }
     }

在文件6的findPersonByIdTest()方法中,首先通过MybatisUtils工具类获取了SqlSession对象,然后通过SqlSession对象的selectOne()方法获取了个人信息。为了查看结果,这里使用了输出语句输出查询结果信息。最后程序执行完毕时,关闭了SqlSession。

使用JUnit4执行findPersonByIdTest()方法后,控制台的输出结果如图4所示。
MyBatis怎样处理一对一关联关系
图4 运行结果

从图4可以看出,使用MyBatis嵌套查询的方式查询出了个人及其关联的身份证信息,这就是MyBatis中的一对一关联查询。

虽然使用嵌套查询的方式比较简单,但是从图4中可以看出,MyBatis嵌套查询的方式要执行多条SQL语句,这对于大型数据集合和列表展示不是很好,因为这样可能会导致成百上千条关联的SQL语句被执行,从而极大的消耗数据库性能并且会降低查询效率。这并不是开发人员所期望的。为此,我们可以使用MyBatis提供的嵌套结果方式,来进行关联查询。

在PersonMapper.xml中,使用MyBatis嵌套结果的方式进行个人及其关联的证件信息查询,所添加的代码如下所示:

<!-- 嵌套结果:使用嵌套结果映射来处理重复的联合结果的子集 -->
<select id="findPersonById2" parameterType="Integer" 
                                   resultMap="IdCardWithPersonResult2">
    SELECT p.*,idcard.code
    from tb_person p,tb_idcard idcard
    where p.card_id=idcard.id 
    and p.id= #{id}
</select>
<resultMap type="Person" id="IdCardWithPersonResult2">
    <id property="id" column="id" />
    <result property="name" column="name" />
    <result property="age" column="age" />
    <result property="sex" column="sex" />
    <association property="card" javaType="IdCard">
        <id property="id" column="card_id" />
        <result property="code" column="code" />
    </association>
</resultMap>

从上述代码中可以看出,MyBatis嵌套结果的方式只编写了一条复杂的多表关联的SQL语句,并且在元素中继续使用相关子元素进行数据库表字段和实体类属性的一一映射。

在测试类MybatisAssociatedTest中,编写测试方法findPersonByIdTest2(),其代码如下所示。

/**
 * 嵌套结果
 */
@Test
public void findPersonByIdTest2() {
    
    // 1、通过工具类生成SqlSession对象
    SqlSession session = MybatisUtils.getSession();
    // 2.使用MyBatis嵌套结果的方法查询id为1的人的信息
    Person person = session.selectOne("com.itheima.mapper." 
                               + "PersonMapper.findPersonById2", 1);
    // 3、输出查询结果信息
    System.out.println(person);
    // 4、关闭SqlSession
    session.close();
}

使用JUnit4执行findPersonByIdTest2()方法后,控制台的输出结果如图5所示。
MyBatis怎样处理一对一关联关系
图5 运行结果

从图5可以看出,使用MyBatis嵌套结果的方式只执行了一条SQL语句,并且同样查询出了个人及其关联的身份证的信息。

MyBatis延迟加载的配置:

在使用MyBatis嵌套查询方式进行MyBatis关联查询映射时,使用MyBatis的延迟加载在一定程度上可以降低运行消耗并提高查询效率。MyBatis默认没有开启延迟加载,需要在核心配置文件mybatis-config.xml中的元素内进行配置,具体配置方式如下:

<settings>
     <!-- 打开延迟加载的开关 -->  
    <setting name="lazyLoadingEnabled" value="true" />  
    <!-- 将积极加载改为消息加载,即按需加载 -->  
    <setting name="aggressiveLazyLoading" value="false"/>  
</settings>

在映射文件中,MyBatis关联映射的元素和元素中都已默认配置了延迟加载属性,即默认属性fetchType=“lazy”(属性fetchType="eager"表示立即加载),所以在配置文件中开启延迟加载后,无需在映射文件中再做配置。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/cz_00001/article/details/118335394

智能推荐

分布式光纤传感器的全球与中国市场2022-2028年:技术、参与者、趋势、市场规模及占有率研究报告_预计2026年中国分布式传感器市场规模有多大-程序员宅基地

文章浏览阅读3.2k次。本文研究全球与中国市场分布式光纤传感器的发展现状及未来发展趋势,分别从生产和消费的角度分析分布式光纤传感器的主要生产地区、主要消费地区以及主要的生产商。重点分析全球与中国市场的主要厂商产品特点、产品规格、不同规格产品的价格、产量、产值及全球和中国市场主要生产商的市场份额。主要生产商包括:FISO TechnologiesBrugg KabelSensor HighwayOmnisensAFL GlobalQinetiQ GroupLockheed MartinOSENSA Innovati_预计2026年中国分布式传感器市场规模有多大

07_08 常用组合逻辑电路结构——为IC设计的延时估计铺垫_基4布斯算法代码-程序员宅基地

文章浏览阅读1.1k次,点赞2次,收藏12次。常用组合逻辑电路结构——为IC设计的延时估计铺垫学习目的:估计模块间的delay,确保写的代码的timing 综合能给到多少HZ,以满足需求!_基4布斯算法代码

OpenAI Manager助手(基于SpringBoot和Vue)_chatgpt网页版-程序员宅基地

文章浏览阅读3.3k次,点赞3次,收藏5次。OpenAI Manager助手(基于SpringBoot和Vue)_chatgpt网页版

关于美国计算机奥赛USACO,你想知道的都在这_usaco可以多次提交吗-程序员宅基地

文章浏览阅读2.2k次。USACO自1992年举办,到目前为止已经举办了27届,目的是为了帮助美国信息学国家队选拔IOI的队员,目前逐渐发展为全球热门的线上赛事,成为美国大学申请条件下,含金量相当高的官方竞赛。USACO的比赛成绩可以助力计算机专业留学,越来越多的学生进入了康奈尔,麻省理工,普林斯顿,哈佛和耶鲁等大学,这些同学的共同点是他们都参加了美国计算机科学竞赛(USACO),并且取得过非常好的成绩。适合参赛人群USACO适合国内在读学生有意向申请美国大学的或者想锻炼自己编程能力的同学,高三学生也可以参加12月的第_usaco可以多次提交吗

MySQL存储过程和自定义函数_mysql自定义函数和存储过程-程序员宅基地

文章浏览阅读394次。1.1 存储程序1.2 创建存储过程1.3 创建自定义函数1.3.1 示例1.4 自定义函数和存储过程的区别1.5 变量的使用1.6 定义条件和处理程序1.6.1 定义条件1.6.1.1 示例1.6.2 定义处理程序1.6.2.1 示例1.7 光标的使用1.7.1 声明光标1.7.2 打开光标1.7.3 使用光标1.7.4 关闭光标1.8 流程控制的使用1.8.1 IF语句1.8.2 CASE语句1.8.3 LOOP语句1.8.4 LEAVE语句1.8.5 ITERATE语句1.8.6 REPEAT语句。_mysql自定义函数和存储过程

半导体基础知识与PN结_本征半导体电流为0-程序员宅基地

文章浏览阅读188次。半导体二极管——集成电路最小组成单元。_本征半导体电流为0

随便推点

【Unity3d Shader】水面和岩浆效果_unity 岩浆shader-程序员宅基地

文章浏览阅读2.8k次,点赞3次,收藏18次。游戏水面特效实现方式太多。咱们这边介绍的是一最简单的UV动画(无顶点位移),整个mesh由4个顶点构成。实现了水面效果(左图),不动代码稍微修改下参数和贴图可以实现岩浆效果(右图)。有要思路是1,uv按时间去做正弦波移动2,在1的基础上加个凹凸图混合uv3,在1、2的基础上加个水流方向4,加上对雾效的支持,如没必要请自行删除雾效代码(把包含fog的几行代码删除)S..._unity 岩浆shader

广义线性模型——Logistic回归模型(1)_广义线性回归模型-程序员宅基地

文章浏览阅读5k次。广义线性模型是线性模型的扩展,它通过连接函数建立响应变量的数学期望值与线性组合的预测变量之间的关系。广义线性模型拟合的形式为:其中g(μY)是条件均值的函数(称为连接函数)。另外,你可放松Y为正态分布的假设,改为Y 服从指数分布族中的一种分布即可。设定好连接函数和概率分布后,便可以通过最大似然估计的多次迭代推导出各参数值。在大部分情况下,线性模型就可以通过一系列连续型或类别型预测变量来预测正态分布的响应变量的工作。但是,有时候我们要进行非正态因变量的分析,例如:(1)类别型.._广义线性回归模型

HTML+CSS大作业 环境网页设计与实现(垃圾分类) web前端开发技术 web课程设计 网页规划与设计_垃圾分类网页设计目标怎么写-程序员宅基地

文章浏览阅读69次。环境保护、 保护地球、 校园环保、垃圾分类、绿色家园、等网站的设计与制作。 总结了一些学生网页制作的经验:一般的网页需要融入以下知识点:div+css布局、浮动、定位、高级css、表格、表单及验证、js轮播图、音频 视频 Flash的应用、ul li、下拉导航栏、鼠标划过效果等知识点,网页的风格主题也很全面:如爱好、风景、校园、美食、动漫、游戏、咖啡、音乐、家乡、电影、名人、商城以及个人主页等主题,学生、新手可参考下方页面的布局和设计和HTML源码(有用点赞△) 一套A+的网_垃圾分类网页设计目标怎么写

C# .Net 发布后,把dll全部放在一个文件夹中,让软件目录更整洁_.net dll 全局目录-程序员宅基地

文章浏览阅读614次,点赞7次,收藏11次。之前找到一个修改 exe 中 DLL地址 的方法, 不太好使,虽然能正确启动, 但无法改变 exe 的工作目录,这就影响了.Net 中很多获取 exe 执行目录来拼接的地址 ( 相对路径 ),比如 wwwroot 和 代码中相对目录还有一些复制到目录的普通文件 等等,它们的地址都会指向原来 exe 的目录, 而不是自定义的 “lib” 目录,根本原因就是没有修改 exe 的工作目录这次来搞一个启动程序,把 .net 的所有东西都放在一个文件夹,在文件夹同级的目录制作一个 exe._.net dll 全局目录

BRIEF特征点描述算法_breif description calculation 特征点-程序员宅基地

文章浏览阅读1.5k次。本文为转载,原博客地址:http://blog.csdn.net/hujingshuang/article/details/46910259简介 BRIEF是2010年的一篇名为《BRIEF:Binary Robust Independent Elementary Features》的文章中提出,BRIEF是对已检测到的特征点进行描述,它是一种二进制编码的描述子,摈弃了利用区域灰度..._breif description calculation 特征点

房屋租赁管理系统的设计和实现,SpringBoot计算机毕业设计论文_基于spring boot的房屋租赁系统论文-程序员宅基地

文章浏览阅读4.1k次,点赞21次,收藏79次。本文是《基于SpringBoot的房屋租赁管理系统》的配套原创说明文档,可以给应届毕业生提供格式撰写参考,也可以给开发类似系统的朋友们提供功能业务设计思路。_基于spring boot的房屋租赁系统论文