首页 > 其他分享 >day07-MyBatis的关联映射01

day07-MyBatis的关联映射01

时间:2023-02-28 23:14:13浏览次数:52  
标签:idencard 01 映射 person day07 public Person MyBatis id

MyBatis的关联映射

Mybatis的关联映射

实际的开发中,对数据库的操作常常会涉及到多张表,这在面向对象中就涉及到了对象与对象之间的关联关系。针对多表之间的操作,MyBatis提供了关联映射,通过关联映射就可以很好的处理对象与对象之间的关联关系。

1.关联关系概述

在关系型数据库中,多表之间存在着三种关系,分别是一对一,一对多,多对多。

image-20230228175005921
  • 一对一:在任意一个表中引入另外一个表的主键作为外键。

  • 一对多:在多个表中都引入了某一个表的主键作为外键

  • 多对多:需要用一张中间表表示多对多的关系,这张中间表引入两张表的主键作为外键。

一般来说一个对象映射一张表,因此一对一的关系就是在A类中定义B类属性,一对多的关系就是在A类中定义List< B> 的属性,多对多就是分别在A、B类中定义对方的List 属性。

2.一对一

一对一关系是一个基本的映射关系,比如Person(人)--IDCard(身份证),我们可以通过如下两种方式实现:

  1. 通过配置XxxMapper.xml实现1对1 [配置方式]
  2. 通过注解的方式实现1对1 [注解方式]

2.1配置方式

2.1.1环境搭建

配置映射文件来实现一对一的映射关系,实现级联查询,要求通过person可以获取到对应的idencard信息

关于级联查询:若表A中有一个外键引用了表B的主键,A表就是子表,B表就是父表。当查询表A的数据时,通过表A的外键将表B的记录也查找出来,这就是级联查询。相应的还有级联删除,当删除B表的记录时,会先将A表中关联的记录删掉

(1)person表和 idencard表

-- 创建 idencard 表
-- 记录身份证
CREATE TABLE `idencard`(
`id` INT PRIMARY KEY AUTO_INCREMENT,
`card_sn` VARCHAR(32) NOT NULL DEFAULT ''
)CHARSET utf8;
INSERT INTO `idencard` VALUES(1,'123456789098765');


-- 创建person表
CREATE TABLE `person`(
`id` INT PRIMARY KEY AUTO_INCREMENT,
`name` VARCHAR(32) NOT NULL DEFAULT '',
`card_id` INT, -- 对应idencard表的主键-id
FOREIGN KEY (`card_id`) REFERENCES idencard (`id`)-- card_id作为外键
)CHARSET utf8;
INSERT INTO `person` VALUES(1,'张三',1);

(2)实体类 IdenCard 和 Person

package com.li.entity;

/**
 * @author 李
 * @version 1.0
 */
public class IdenCard {
    private Integer id;
    private String card_sn;
    //省略setter,getter,toString方法
}
package com.li.entity;

/**
 * @author 李
 * @version 1.0
 */
public class Person {
    private Integer id;
    private String name;
    private IdenCard card;
    //省略setter,getter,toString方法
}

(3)PersonMapper 接口

package com.li.mapper;

import com.li.entity.Person;

/**
 * @author 李
 * @version 1.0
 */
public interface PersonMapper {
    //通过Person的id获取到Person,包括这个Person关联的IdenCard对象(级联操作)
    public Person getPersonById(Integer id);
}

2.1.2方式1:多表联查

mybatis – MyBatis 3 | XML 映射器

PersonMapper.xml映射文件实现级联查询,实现方法是使用多表联查,返回的数据通过resultMap结果映射

<mapper namespace="com.li.mapper.PersonMapper">
    <!--1.接口声明:public Person getPersonById(Integer id);
        2.通过Person的id获取到Person,包括这个Person关联的IdenCard对象(级联操作)
        3.返回类型如果配置成resultType="Person",不能实现级联查询,
		在返回的person对象中IdenCard属性对象为 null
        4.因此需要使用自定义resultMap,在resultMap中指定级联关系-->
    <select id="getPersonById" parameterType="Integer" resultMap="PersonResultMap">
        SELECT * FROM `person`,`idencard` WHERE `person`.`id`= #{id} AND
        `person`.`card_id` = `idencard`.`id`;
    </select>

    <!--association – 一个复杂类型的关联;许多结果将包装成这种类型嵌套结果映射 – 关联可以是
		resultMap 元素,或是对其它结果映射的引用
    	1.property="card" 表示 Person对象的card属性
    	2.javaType="IdenCard" 表示card属性的类型-->
    <resultMap id="PersonResultMap" type="Person">
        <!--id标签–一个ID结果(就是主键);标记出作为主键的结果可以帮助提高整体性能-->
         <!--这里的property表示Person类的属性名,column表示对应表的字段-->
        <id property="id" column="id"/>
        <result property="name" column="name"/>
        <association property="card" javaType="IdenCard">
            <!--这里的property表示IdenCard类的属性名,column表示表的字段名-->
            <result property="id" column="id"/>
            <result property="card_sn" column="card_sn"/>
        </association>
    </resultMap>
</mapper>

测试:

@Test
public void getPersonById() {
    Person person = personMapper.getPersonById(1);
    System.out.println("person=" + person);
    if (sqlSession != null) {
        sqlSession.close();
    }
}
image-20230228194043902

2.2.3方式2:分解为多次单表操作(推荐使用)

第一种方式使用了多表联查的形式实现级联查询,但是如果涉及的表过多,sql语句可读性就会变差。第二种方式的核心思想是将多表联查分解成单表操作,这样更简洁,易于维护,而且可以复用你写好的方法,推荐使用

(1)创建IdenCardMapper接口

public interface IdenCardMapper {
    //根据id获取到身份证序列号
    public IdenCard getIdenCardById(Integer id);
}

(2)在IdenCardMapper的映射文件中实现该方法

<mapper namespace="com.li.mapper.IdenCardMapper">
    <!--配置实现public IdenCard getIdenCardById(Integer id);-->
    <select id="getIdenCardById" parameterType="Integer" resultType="IdenCard">
        SELECT * FROM `idencard` WHERE `id` = #{id}
    </select>
</mapper>

(3)PersonMapper接口

//通过Person的id获取到Person,包括这个Person关联的IdenCard对象(方式2)
public Person getPersonById2(Integer id);

(4)实现PersonMapper接口的映射文件

   1. 先通过 SELECT * FROM person WHERE id =#{id} 返回 person 信息
   2. 以第一个操作返回的 card_id 字段数据,作为条件再次查询,得到对应的 IdenCard 数据

如果第一个操作使用了别名,那么返回的时候的字段也是别名,因此第二个操作也要使用别名才能匹配到

<!--通过Person的id获取到Person,包括这个Person关联的IdenCard对象(方式2)
    接口方法:public Person getPersonById2(Integer id);-->
<resultMap id="PersonResultMap2" type="Person">
    <id property="id" column="id"/>
    <result property="name" column="name"/>
    <!--第二种方式的核心思想是将多表联查操作分解成单表操作,
    这样更简洁,易于维护,复用性更强,推荐使用-->
    <!--1.property="card"表示Person对象的card属性
        2.column="card_id"是SELECT * FROM person WHERE id = #{id}语句返回的card_id字段名/别名
        3.返回的字段card_id信息/数据会作为getIdenCardById()的入参来执行方法-->
    <association property="card" column="card_id"
                 select="com.li.mapper.IdenCardMapper.getIdenCardById"/>
</resultMap>
<select id="getPersonById2" parameterType="Integer" resultMap="PersonResultMap2">
    SELECT * FROM person WHERE id = #{id};
</select>

测试结果:

可以看到底层执行了两次sql查询操作。首先对person表进行查询,查询结果(card_id)作为第二张表的查询条件(id),再对idencard表进行查询。

image-20230228204133095

2.2注解方式

通过注解的方式来实现一对一的映射关系,实现级联查询,通过person可以获取到对应的idencard的信息。这里只进行方式二的演示。

在实际开发中还是推荐使用配置方式

(1)注解实现方法

IdenCardMapperAnnotation 接口:

package com.li.mapper;

import com.li.entity.IdenCard;
import org.apache.ibatis.annotations.Select;

/**
 * @author 李
 * @version 1.0
 * 使用注解的方式实现一对一的映射
 */
public interface IdenCardMapperAnnotation {
    //根据id获取到身份证序列号
    @Select(value = "SELECT * FROM `idencard` WHERE `id` = #{id}")
    public IdenCard getIdenCardById(Integer id);
}

PersonMapperAnnotation 接口:

package com.li.mapper;

import com.li.entity.Person;
import org.apache.ibatis.annotations.One;
import org.apache.ibatis.annotations.Result;
import org.apache.ibatis.annotations.Results;
import org.apache.ibatis.annotations.Select;

/**
 * @author 李
 * @version 1.0
 */
public interface PersonMapperAnnotation {
    //通过Person的id获取到Person,包括这个Person关联的IdenCard对象
    //注解的形式就是对前面xml配置方式的体现
    @Select(value = "SELECT * FROM person WHERE id = #{id}")//如果这里返回的字段使用了别名,则@result的card_id也要使用该别名
    @Results({//配置返回数据的映射
            @Result(id = true, property = "id", column = "id"),
            @Result(property = "name", column = "name"),
            @Result(property = "card", column = "card_id",
                    one = @One(select = "com.li.mapper.IdenCardMapper.getIdenCardById"))
    })
    public Person getPersonById(Integer id);
}

(2)测试

@Test
public void getIdenCardById() {
    Person person = personMapperAnnotation.getPersonById(1);
    System.out.println("person=" + person);
    if (sqlSession != null) {
        sqlSession.close();
    }
}
image-20230228210319588

2.3注意事项

一张表是否设置了外键,对MyBatis进行对象级联映射没有影响,外键只是对表本身数据的约束

2.4练习

前面我们讲解的是查询Person可以级联查询到IdenCard,如果要求通过查询IdenCard,也可以级联查询到Person,应该如何解决?

标签:idencard,01,映射,person,day07,public,Person,MyBatis,id
From: https://www.cnblogs.com/liyuelian/p/17166430.html

相关文章

  • mybatis:自定义映射关系resultMap
    创建表t_emp定义实体类packageorg.example.entity;publicclassEmp{privateIntegerempId;privateStringempName;privateIntegerage;pr......
  • mybatis自增主键的获取
    实体类packageorg.example.entity;publicclassUser{privateIntegerid;privateStringname;privateintage;privateStringgender;p......
  • 【Mybatis】【配置文件解析】【四】Mybatis源码解析-mappers的解析四(绑定Mapper、处理
    1 前言我们上节把我们mapper里的sql节点以及我们的增删改查都解析了,那么最后回来就剩下两块没看了,一块是我们的mapper跟我们的接口绑定,一块就是我们在解析的过程中......
  • SSM框架-MyBatis学习日记6
    多对一的处理多对一的理解:多个学生对应一个老师如果对于学生这边,就是一个多对一的现象,即从学生这边关联一个老师!数据库设计CREATE TABLE `teacher`(`id` INT(10)......
  • mybatis入门
    一、MyBatis简介​ MyBatis本是apache的一个开源项目iBatis,2010年这个项目由apachesoftwarefoundation迁移到了googlecode,并且改名为MyBatis。2013年11月迁移到Github......
  • BUUctf pwn1_sctf_2016 nc尝试
    BUUctfpwn1_sctf_2016file,发现文件是32位elfchecksec,发现文件开启了NX保护,NX指的是NoExcute(禁止运行)IDA查看函数,发现main()调用了vuln(),而且存在一个get_flag函数,地......
  • mybatis-plus主键生成策略(实体类配置,数据库插入数据自动生成id)
    转载:MyBatisplus--ActiveRecord(AR)_mybatisplusidtype.auto_憨憨浩浩的博客-CSDN博客0.auto:自动增长(mysql,sqlserver)1.none:没有主键2.input:手动输入3.id_worker:实体......
  • 恒创科技:服务器常见错误代码501什么意思?怎么解决?
    ​作为网站所有者,很少有情况比打开您的网站时收到HTTP错误代码更令人恼怒和困惑,除非您精通网站运营的后端基础设施和网络配置方面。对于501NotImplementedHTTP......
  • 课堂练习01题目:计算最长英语单词链总结
     一、题目内容:大家经常玩成语接龙游戏,我们试一试英语的接龙吧:一个文本文件中有N个不同的英语单词,我们能否写一个程序,快速找出最长的能首尾相连的英语单词链,每个单词......
  • [洛谷]P5401 [CTS2019] 珍珠 题解
    [洛谷]P5401[CTS2019]珍珠题解题意概述有\(D\)种珍珠,每种有无限颗,现在等概率的从\(D\)种珍珠中抽\(n\)次珍珠,每次抽\(1\)个珍珠,记第\(i\)种珍珠最后一共抽......