mybatis05_对应关系

发布时间 2023-03-23 11:48:19作者: Purearc

一、一对一关系

以身份证和人为例

1、resultType实现

​ 使用resultType实现,将所需要的属性放到一个实体类中。

⬇️创建数据表

CREATE TABLE `id_card` (
  `id` int NOT NULL AUTO_INCREMENT,
  `card_num` varchar(255) COLLATE utf8mb4_general_ci DEFAULT NULL,
  `person_id` int DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;

CREATE TABLE `person` (
  `id` int NOT NULL AUTO_INCREMENT,
  `person_name` varchar(255) COLLATE utf8mb4_general_ci DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;

⬇️实体类 Person

import lombok.Data;
import lombok.experimental.Accessors;

@Data
@Accessors(chain = true)
public class Person {
    private Integer id;
    private String personName;
}

⬇️实体类 IdCard 继承自 Person 使 IdCard 中可以获得 Person中的对象信息;重写 toString 调用父类Person的方法获得 personName。

import lombok.Data;
import lombok.experimental.Accessors;

@Data
@Accessors(chain = true)
public class IdCard extends Person{
    private Integer id;
    private String cardNum;

    @Override
    public String toString() {
        return "IdCard{" +
                "cardNum='" + cardNum + '\'' + "personName=" + super.getPersonName() +
                '}';
    }
}

⬇️mapper映射

    <select id="list" resultType="com.ls.pojo.IdCard">
        select card_num cardNum,person_name personName
        from id_card
        join person
        on id_card.id = person.id
    </select>

⬇️测试

    private static void testList() {
        SqlSession sqlSession = null;
        try {
            sqlSession = MybatisUtil.getSqlSession();
            IdCardMapper idCardMapper = sqlSession.getMapper(IdCardMapper.class);
            List<IdCard> cardList = idCardMapper.list();
            cardList.stream().forEach(System.out::println);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (sqlSession != null) {sqlSession.close();}
        }
    }

⬇️编译后的sql语句和结果

image-20230316100004281

2、resultMap实现

​ 使用 resultType 实现的方式,无非就是将要获取的信息数据字段,都对应到一个扩展 Bean 中,同时还要保持字段名与列名保持一致。这里我们让 IdCardExtends 来获得 IdCard2 的信息(继承),并重写 IdCard 的 toString方法让其能够表现出父类(super)的属性。

import lombok.Data;
import lombok.experimental.Accessors;

@Data
@Accessors(chain = true)
public class IdCard2 {
    private Integer id;
    private String cardNum;
}

import lombok.Data;
import lombok.experimental.Accessors;

@Data
@Accessors(chain = true)
public class IdCardExtends extends IdCard2{
    Person person;

    @Override
    public String toString() {
        return "IdCardExtends{" +
                "person=" + person + "super:"+super.toString()+
                '}';
    }
}

⬇️定义 resultMap 和 sql 语句

​ 注意指明是哪张表的 id 不然会有Column 'id' in field list is ambiguous。(顺便问一句万能的网友为什么把这个 id_card.id 属性列去掉筛选出来的就全是 null 呢)

使用 association 映射关联查询单个对象的信息

​ property 属性:要将关联查询的对象信息映射到 person 对象的哪个属性上

​ javaType 属性:要将关联查询的对象信息映射成哪种 Java 类

    <resultMap id="IdCardMap" type="com.ls.pojo.IdCardExtends">
        <id property="id" column="id"></id>
        <result property="cardNum" column="card_num"></result>
        <association property="person" javaType="com.ls.pojo.Person">
            <id column="id" property="id"></id>
            <result column="person_name" property="personName"></result>
        </association>
    </resultMap>

    <select id="list2" resultMap="IdCardMap">
        select  id_card.id,card_num cardNum, person_name personName
        from id_card
                 join person
                      on id_card.id = person.id
    </select>

⬇️测试程序


    private static void testList2() {
        SqlSession sqlSession = null;
        try {
            sqlSession = MybatisUtil.getSqlSession();
            IdCardMapper idCardMapper = sqlSession.getMapper(IdCardMapper.class);
            List<IdCardExtends> cardListExtends = idCardMapper.list2();
            cardListExtends.stream().forEach(System.out::println);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (sqlSession != null) {sqlSession.close();}
        }
    }

⬇️

image-20230316155422413

二、一对多关系

​ 以部门与员工之间的关系为例

​ 如果不使用框架进行一对多的联合查询则需要:先调用 dao 层查询部门表,然后再根据部门表与员工表的主外键关联字段,再调用员工表的 dao 再查询员工表数据,最终完成数据组装。

⬇️使用到的数据库如下

CREATE TABLE `emp` (
  `emp_id` bigint NOT NULL AUTO_INCREMENT,
  `emp_name` varchar(255) COLLATE utf8mb4_general_ci DEFAULT NULL,
  `address` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `email` varchar(255) COLLATE utf8mb4_general_ci DEFAULT NULL,
  `create_time` datetime DEFAULT NULL,
  `update_time` datetime DEFAULT NULL,
  `dept_id` bigint DEFAULT NULL,
  PRIMARY KEY (`emp_id`)
) ENGINE=InnoDB AUTO_INCREMENT=16 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;

CREATE TABLE `dept` (
  `dept_id` bigint NOT NULL AUTO_INCREMENT,
  `dept_name` varchar(255) COLLATE utf8mb4_general_ci DEFAULT NULL,
  `location` varchar(255) COLLATE utf8mb4_general_ci DEFAULT NULL,
  PRIMARY KEY (`dept_id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;

⬇️实体类有部门和员工两个,其中部门中应有一个List的员工列表作为其属性

import lombok.Data;
import lombok.experimental.Accessors;

import java.util.List;

@Data
@Accessors(chain = true)
public class Dept {
    private Long deptId;
    private String deptName;
    private String location;
    //一个部门多个员工
    private List<Emp> empList;
}

import lombok.Data;
import lombok.experimental.Accessors;

import java.util.Date;

@Data
@Accessors(chain = true)
public class Emp {
    private Long empId;
    private String empName;
    private String address;
    private String email;
    private Date createTime;
    private Date updateTime;
    private Long deptId;
}

⬇️mapper映射文件,配置关联查询 Orders 信息的映射,使用 collection 映射关联查询多个对象的信息

​ property 属性:要将关联查询的对象信息映射到 ordersUser 对象的哪个属性上

​ ofType 属性:要将关联查询的对象信息映射成哪种 Java 类

import com.ls.pojo.Dept;
import com.ls.pojo.Emp;

import java.util.List;

public interface DeptMapper {
    /**
     * 根据部门id查部门的信息
     * 包括部门的员工的信息
     * @param deptId
     * @return
     */
    List<Dept> findById(Long deptId);
}
    <resultMap id="DeptMap" type="com.ls.pojo.Dept">
        <id property="deptId" column="dept_id"></id>
        <result property="deptName" column="dept_name"></result>
        <result property="location" column="location"></result>
        <collection property="empList" ofType="com.ls.pojo.Emp">
            <id column="emp_id" property="empId"></id>
            <result column="emp_name" property="empName"></result>
            <result column="address" property="address"></result>
            <result column="create_tiem" property="createTime"></result>
            <result column="update_time" property="updateTime"></result>
        </collection>
    </resultMap>
    <select id="findById" resultMap="DeptMap">
        select emp.*,dept.* from dept join emp
            on dept.dept_id = emp.dept_id
                where dept.dept_id = #{deptId}
    </select>

⬇️测试

​ 这里以根据 id 查询部门信息为例,部门信息中应该包含所有员工的信息

    private static void testFindById() {
        SqlSession sqlSession = null;
        try {
            sqlSession = MybatisUtil.getSqlSession();
            DeptMapper deptMapper = sqlSession.getMapper(DeptMapper.class);
            List<Dept> deptList = deptMapper.findById(1L);
            deptList.stream().forEach(System.out::println);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (sqlSession != null) {sqlSession.close();}
        }
    }

⬇️测试结果

image-20230321191548885

三、多对多关系

​ 暂时略,毕竟联合查询降低性能,日后面试题补上。