MyBatis-映射关系

  |   0 评论   |   0 浏览

MyBatis-映射关系

1.映射关系一对一

1.映射关系-官方文档

文档地址: https://mybatis.org/mybatis-3/zh/sqlmap-xml.html

2.映射关系1对1-基本介绍

● 基本介绍

  1. 项目中 1 对 1 的关系是一个基本的映射关系,比如:Person(人) --- IDCard(身份证)
-- 创建 mybatis_idencard 表
CREATE TABLE idencard ( id INT PRIMARY KEY AUTO_INCREMENT, card_sn VARCHAR ( 32 ) NOT NULL DEFAULT '' ) CHARSET utf8;
CREATE TABLE person (
	id INT PRIMARY KEY AUTO_INCREMENT,
	NAME VARCHAR ( 32 ) NOT NULL DEFAULT '',
	card_id INT,
FOREIGN KEY ( card_id ) REFERENCES idencard ( id ) 
) CHARSET utf8;

INSERT INTO idencard
VALUES
	( 1, '111111111111110' );
INSERT INTO person
VALUES
	( 1, '张三', 1 );
	
SELECT * FROM person; 
SELECT * FROM idencard
  1. 创建新的 module(mybatis-mapping), 相关配置文件可以从上一个 module 拷贝

    image-20220707222027751

​ 3.创建src\main\java\com\llp\entity\IdenCard.java

@Data
public class IdenCard {
    private Integer id;
    private String card_sn;
}

​ 4.创建src\main\java\com\llp\entity\Person.java

@Data
public class Person {
    private Integer id;
    private String name;
    //因为我们的需要实现一个级联操作, 一个人需要对应一个身份证
    //这里需要直接定义IdenCard对象属性
    private IdenCard card;
}

​ 5.创建PersonMapper.java和IdenCardMapper.java

public interface PersonMapper {
    Person getPersonById(Integer id);
}

public interface IdenCardMapper {
    IdenCard getIdenCardById(Integer id);
}

​ 6.创建PersonMapper.xml和IdenCardMapper.xml

IdenCardMapper.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.llp.mapper.IdenCardMapper">
    <!--
        1、配置/实现//根据id获取到身份证序列号
        2、public IdenCard getIdenCardById(Integer id);
    -->
<select id="getIdenCardById" resultType="com.llp.entity.IdenCard">
    SELECT * FROM `idencard` WHERE `id` = #{id}
</select>
</mapper>

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.llp.mapper.PersonMapper">
    <!--
        1、配置/实现//根据id获取到身份证序列号
        2、public IdenCard getIdenCardById(Integer id);
    -->
<select id="getPersonById" resultType="com.llp.entity.Person">
   select * from person where id = #{id}
</select>
</mapper>

​ 7.测试类

@Test
public void getIdenCardById(){
    IdenCard idenCardById = idenCardMapper.getIdenCardById(1);
    //IdenCard(id=1, card_sn=111111111111110)
    System.out.println(idenCardById);
}

@Test
public void getPersonById(){
    Person personById = personMapper.getPersonById(1);
    //Person(id=1, name=张三, card=null)
    System.out.println(personById);
}

Person.java中包含了IdenCard类型的字段,当我们直接使用如下方式

<select id="getPersonById" resultType="com.llp.entity.Person">
   select * from person where id = #{id}
</select>

去获取person对象时,发现mybatis并不能将person类中的IdenCard对象的值映射到card属性中,由此就引出了处理1对1的映射方式

3.映射关系 1 对 1-映射方式

1.映射方式

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

2.配置 Mapper.xml 的方式-应用实例

1.方式1

说明:通过配置 XxxMapper.xml 的方式来实现下面的 1 对 1 的映射关系,实现级联查询,通过 person 可以获取到对应的 idencard 信息

1.修改PersonMapper.xml

<!--
1、根据id获取到身份证序列号, 并查询级联的person
2、public IdenCard getIdenCardById2(Integer id);
3. 自定义一个resultMap , 完成属性值映射
-->
<resultMap id="personResultMap" type="com.llp.entity.Person">
       <!--id – 一个 ID 结果;标记出作为 ID 的结果可以帮助提高整体性能
           1.property="id" 表示person 属性 id ,通常是主键
           2.column="id" 表示对应表的字段
       -->
   <id property="id" column="id"/>
   <result property="name" column="name"/>
    <!--association – 一个复杂类型的关联
        1. property="card" 表示 Person对象的 card 属性
        2. javaType="IdenCard" 表示card 属性 的类型
        3. column="id" 是从我们的 下面这个语句查询后返回的字段
        SELECT *  FROM `person`,`idencard` WHERE `person`.id=1
        AND `person`.card_id = `idencard`.id
       -->
   <association property="card" javaType="com.llp.entity.IdenCard">
   <id property="id" column="id"/>
   <result property="card_sn" column="card_sn"/>
   </association>
</resultMap>
<select id="getPersonById" resultMap="personResultMap">
   select * from person,idencard where person.id = #{id} and person.card_id=idencard.id
</select>

2.测试方法

@Test
public void getPersonById(){
    Person personById = personMapper.getPersonById(1);
    //Person(id=1, name=张三, card=IdenCard(id=1, card_sn=111111111111110))
    System.out.println(personById);
}
2.方式2

1.修改PersonMapper.xml

<!--
        1、通过Person的id获取到Person,包括这个Person关联的IdenCard对象,方式2
        2、public Person getPersonById2(Integer id);
        3. 这里的方式和前面不同.
        1) 先通过 SELECT * FROM `person` WHERE `id` = #{id} 返回 person信息
        2) 再通过 返回的card_id 值,再执行操作,得到IdenCard 数据
    -->
	<resultMap id="personResultMap2" type="com.llp.entity.Person">
		<id property="id" column="id"/>
		<result property="name" column="name"/>
        <!--
        1. mybatis第二种方式核心思想: 将这个多表联查,分解成单表操作 , 这样简洁,而且易于维护 ,推荐
        2. 而且可以复用你已经写好的方法 -组合
        3. property="card": 表示 Person对象的 card 属性
        4. column="card_id" 这个是
        SELECT * FROM `person` WHERE `id` = #{id}  返回的 字段 card_id 信息/数据
        5. 返回的 字段 card_id 信息/数据 作为getIdenCardById入参 和 IdenCard进行关联, 来执行
        -->

		<association property="card" column="card_id" javaType="com.llp.entity.IdenCard" select="com.llp.mapper.IdenCardMapper.getIdenCardById"/>
	</resultMap>
	<select id="getPersonById2" resultMap="personResultMap2">
		select * from person where id = #{id}
	</select>

2.测试方法

@Test
public void getPersonById2(){
    Person personById2 = personMapper.getPersonById2(1);
    //Person(id=1, name=张三, card=IdenCard(id=1, card_sn=111111111111110))
    System.out.println(personById2);
}

3.注解的方式实现-应用实例

● 通过注解的方式实现-应用实例

通过注解的方式来实现下面的 1 对 1 的映射关系,实现级联查询,通过 person 可以获取到对应的 identcard 信息,在实际开发中还是推荐使用配置方式

1.创建src\main\java\com\llp\mapper\PersonMapperAnnotation.java

public interface PersonMapperAnnotation {
	//注解的形式就是对前面xml配置方式的体现
    @Select("select * from person where id = #{id}")
    @Results({
            //id=true 返回是否为 id 列
        @Result(id = true,property = "id",column = "id"),
        @Result(property = "name",column = "name"),
            //one 一对一映射定义,集合关系的映射定义,select可以写注解的方法:com.llp.mapper.IdenCardMapperAnnotation.getIdenCardById
           //也可以写xml配置的方法
        @Result(property = "card",column = "card_id",one = @One(select = "com.llp.mapper.IdenCardMapper.getIdenCardById"))
    })
    Person getPersonById(Integer id);

}

2.测试方法

@Test
public void getPersonById(){
   //Person(id=1, name=张三, card=IdenCard(id=1, card_sn=111111111111110))
   Person personById = personMapperAnnotation.getPersonById(1);
   System.out.println(personById);
}

4.注意事项和细节

  1. 表是否设置外键, 对 MyBatis 进行对象/级联映射没有影响
  2. 举例: 去掉 person 表的外键 , 进行测试, 依然可以获取相应的级联对象

2.映射关系多对一

1.映射关系-官方文档

文档地址:https://mybatis.org/mybatis-3/zh/sqlmap-xml.html

2.映射关系多对1-基本介绍

● 基本介绍

  1. 项目中多对 1 的关系是一个基本的映射关系, 多对 1, 也可以理解成是 1 对多.
  2. User --- Pet: 一个用户可以养多只宠物 3. Dep ---Emp : 一个部门可以有多个员工

● 注意细节

  1. 在实际的项目开发中, 要求会使用双向的多对一的映射关系
  2. 什么是双向的多对一的关系 : 比如通过 User 可以查询到对应的 Pet, 反过来,通过 Pet 也可以级联查询到对应的 User 信息.
  3. 多对多的关系,在多对1 的基础上扩展即可.

3.映射关系多对1-映射方式

1.映射方式

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

2.配置Mapper.xml方式

需求说明: 实现级联查询,通过 user 的 id 可以查询到用户信息,并可以查询到关联的 pet 信息,反过来,通过 Pet 的 id 可以查询到 Pet 的信息,并且可以级联查询到它的主人 User 对象信息

  1. 创建 mybatis_user 和 mybatis_pet 表
-- 创建user表
CREATE TABLE mybatis_user ( id INT PRIMARY KEY AUTO_INCREMENT, NAME VARCHAR ( 32 ) NOT NULL DEFAULT '' ) CHARSET = utf8;
-- 创建宠物表
CREATE TABLE mybatis_pet (
	id INT PRIMARY KEY AUTO_INCREMENT,
	nickname VARCHAR ( 32 ) NOT NULL DEFAULT '',
	user_id INT,
FOREIGN KEY ( user_id ) REFERENCES mybatis_user ( id ) 
) CHARSET = utf8;

-- 插入用户
INSERT INTO mybatis_user VALUES ( NULL, '宋江' ),(NULL,'张飞');
	
-- 插入宠物
INSERT INTO mybatis_pet VALUES ( 1, '黑背', 1 ),( 2, '小哈', 1 );
INSERT INTO mybatis_pet VALUES ( 3, '波斯猫', 2 ),( 4, '贵妃猫', 2 );
	
SELECT * FROM mybatis_user; 
	
SELECT * FROM mybatis_pet;

image-20220709125730135

image-20220709125828574

2.创建Pet.java、User.java

这里不使用toString方法是为了后面pet和user相互调用导致内存溢出statckOverFlow

@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class User {
    private Integer id;
    private String name;
    private List<Pet> petList;
}
@Data
public class Person {
    private Integer id;
    private String name;
    //因为我们的需要实现一个级联操作, 一个人需要对应一个身份证
    //这里需要直接定义IdenCard对象属性
    private IdenCard card;
}

3.创建UserMapper.java和PetMapper.java

public interface UserMapper {

    //通过id获取User对象
    public User getUserById(Integer id);

}
public interface PetMapper {

    //通过User的id来获取pet对象,可能有多个,因此使用List接收
    public List<Pet> getPetByUserId(Integer userId);
    //通过pet的id获取Pet对象, 同时会查询到pet对象关联的user对象
    public Pet getPetById(Integer id);
}

4.创建UserMapper.xml和PetMapper.xml

PetMapper.xml

<mapper namespace="com.llp.mapper.PetMapper">

    <!--
        1、通过User的id来获取pet对象,可能有多个,因此使用List接收
        2、public List<Pet> getPetByUserId(Integer userId);
		3、pet表中包含user_id字段,而一个user_id对应一个用户,所有这里使用association进行级联
    -->
    <resultMap id="PetResultMap" type="Pet">
        <id property="id" column="id"/>
        <result property="nickname" column="nickname"/>
        <association property="user" column="user_id"
                     select="com.llp.mapper.UserMapper.getUserById" />
    </resultMap>
    <select id="getPetByUserId" parameterType="Integer" resultMap="PetResultMap">
        SELECT * FROM `mybatis_pet` WHERE `user_id` = #{userId}
    </select>

    <!--
        1. 注意体会resultMap带来好处, 直接复用
        2. 实现/配置public Pet getPetById(Integer id);
        3. 通过pet的id获取Pet对象
    -->
    <select id="getPetById"
            parameterType="Integer"
            resultMap="PetResultMap">
        SELECT * FROM `mybatis_pet` WHERE `id` = #{id}
    </select>
</mapper>

UserMapper.xml

<mapper namespace="com.llp.mapper.UserMapper">

    <!--
    1、配置/实现 public User getUserById(Integer id);
    2、思路(1) 先通过user-id 查询得到user信息 (2) 再根据user-id查询对应的pet信息
      并映射到User-List<Pet> pets
    -->
    <resultMap id="UserResultMap" type="User">
        <id property="id" column="id"/>
        <result property="name" column="name"/>
        <!--因为pets属性是集合,因此这里需要是collection标签来处理
        1. ofType="Pet" 指定返回的集合中存放的数据类型Pet
        2. collection 表示 pets 是一个集合
        3. property="pets" 是返回的user对象的属性 pets
        4. column="id" SELECT * FROM `mybatis_user` WHERE `id` = #{id} 返回的id字段对应的值
		5. collection 标签中填写column="id",这里id是指的用户id,而一个用户对应多个宠物因此user表中设计的是集合类型
        -->
        <collection property="pets" column="id" ofType="Pet"
                    select="com.llp.mapper.PetMapper.getPetByUserId"/>
    </resultMap>
    <select id="getUserById" parameterType="Integer" resultMap="UserResultMap">
        SELECT * FROM `mybatis_user` WHERE `id` = #{id}
    </select>

5.创建UserMapperTest.java和PetMapperTest.java测试类

PetMapperTest.java

@Test
public void getPetByUserId() {
    List<Pet> pets = petMapper.getPetByUserId(2);
    for (Pet pet : pets) {
        System.out.println("pet信息-" + pet.getId() + "-" + pet.getNickName());
        User user = pet.getUser();
        System.out.println("user信息 name-" + user.getName());
    }
    if(sqlSession != null) {
        sqlSession.close();
    }
}
@Test
public void getPetById() {
    Pet pet = petMapper.getPetById(2);
    System.out.println("pet信息-" + pet.getId() + "-" + pet.getNickName());
    User user = pet.getUser();
    System.out.println("user信息-" + user.getId() + "-" + user.getName());
    if(sqlSession != null) {
        sqlSession.close();
    }
}

UserMapperTest.java

@Test
    public void getUserById() {
        User user = userMapper.getUserById(2);

        System.out.println("user信息-" + user.getId() + "-" + user.getName());

        List<Pet> pets = user.getPetList();
        for (Pet pet : pets) {
            System.out.println("养的宠物信息-" + pet.getId() + "-" + pet.getNickName());
        }
        if(sqlSession != null) {
            sqlSession.close();
        }
    }

image-20220709135631752

3.注解实现多对1映射-应用实例

需求说明: 通过注解的方式来实现下面的多对 1 的映射关系,实现级联查询,完成前面完成 的任务,通过 User-->Pet 也可 Pet->User , 在实际开发中推荐使用配置方式来做

1.创建src\main\java\com\llp\mapper\PetMapperAnnotation.java

public interface PetMapperAnnotation {

    /**
     * <resultMap id="petResultMap" type="com.llp.entity.Pet">
     * <id column="id" property="id"/>
     * <result column="nickname" property="nickName"/>
     * <association property="user" column="user_id" select="com.llp.mapper.MyBatisUserMapper.getUserById"></association></resultMap>
     * <select id="getPetByUserId" resultMap="petResultMap">
     * SELECT * FROM mybatis_pet where user_id=#{userId};
     * </select>
     *
     * @param userId
     * @return
     */
    @Select(value = "SELECT * FROM mybatis_pet where user_id=#{userId}")
    @Results({
            @Result(id = true, column = "id", property = "id"),
            @Result(column = "nickname", property = "nickName"),
            @Result(property = "user", column = "user_id", one = @One(select = "com.llp.mapper.MyBatisUserMapper.getUserById"))
    })
    List<Pet> getPetByUserId(Integer userId);

    @Select(value = "SELECT * FROM mybatis_pet where id=#{id}")
    @Results({
            @Result(id = true, column = "id", property = "id"),
            @Result(column = "nickname", property = "nickName"),
            @Result(property = "user", column = "user_id",  
                    one = @One(select = "com.llp.mapper.MyBatisUserMapper.getUserById"))
    })
    Pet getPetById(int id);

}

2.创建src\main\java\com\llp\mapper\UserMapperAnnotation.java

public interface UserMapperAnnotation {

    /**
     * <resultMap id="userResultMap" type="com.llp.entity.User">
     * <id column="id" property="id"/>
     * <result column="name" property="name"/>
     * <collection column="id" property="petList" ofType="com.llp.entity.Pet" select="com.llp.mapper.PetMapper.getPetByUserId"/>
     * </resultMap>
     * <select id="getUserById" resultMap="userResultMap">
     * select * from mybatis_user where id = #{id}
     * </select>
     * @param id
     * @return
     */
    @Select("select * from mybatis_user where id = #{id}")
    @Results({
            @Result(id = true,column = "id",property = "id"),
            @Result(column = "name",property = "name"),
            @Result(column = "id",property = "petList",many = @Many(select ="com.llp.mapper.PetMapper.getPetByUserId"))
    })
    User getUserById(Integer id);
}

3.测试方法

PetMapperAnnotationTest.java

@Test
public void getPetByUserId(){
    List<Pet> pets = personMapperAnnotation.getPetByUserId(2);
    for (Pet pet : pets) {
        System.out.println("pet信息-" + pet.getId() + "-" + pet.getNickName());
        User user = pet.getUser();
        System.out.println("user信息 name-" + user.getName());
    }
    if(sqlSession != null) {
        sqlSession.close();
    }
}

image-20220709141613713

@Test
public void getPetById() {
    Pet pet = personMapperAnnotation.getPetById(2);
    System.out.println("pet信息-" + pet.getId() + "-" + pet.getNickName());
    User user = pet.getUser();
    System.out.println("user信息-" + user.getId() + "-" + user.getName());
    if(sqlSession != null) {
        sqlSession.close();
    }
}

image-20220709141706304

UserMapperAnnotationTest

@Test
public void getUserById() {
    User user = userMapperAnnotation.getUserById(2);

    System.out.println("user信息-" + user.getId() + "-" + user.getName());

    List<Pet> pets = user.getPetList();
    for (Pet pet : pets) {
        System.out.println("养的宠物信息-" + pet.getId() + "-" + pet.getNickName());
    }
    if(sqlSession != null) {
        sqlSession.close();
    }
}

image-20220709141453469


标题:MyBatis-映射关系
作者:llp
地址:https://llinp.cn/articles/2022/07/07/1657208324786.html