如何在MyBatis中处理复杂结果集映射关系

这篇具有很好参考价值的文章主要介绍了如何在MyBatis中处理复杂结果集映射关系。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言

在开发中,我们不是总是对单表进行操作的场景。按照数据库表的设计原则,要符合一定的范式,那么就需要对某一种场景的表进行拆分。
在业务上,可能是属于同一个业务。但是,在数据库中表的存储这块,可能就会涉及到表的拆分。
这里设计到表的创建直接创建两张表:

一、 准备工作

  1. 对于如何搭建MyBatis的测试环境,在博文从0到1搭建MyBatis实例思路剖析中有详细的介绍,这里就不一一的进行展开。
  2. MySQL数据库中创建两张表作为本次测试所需要的环境基础。
    在第一步的基础上,我们导入两张表。一张是t_dept,另一张是t_emp
    t_dept
DROP TABLE IF EXISTS `t_dept`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `t_dept` (
  `did` int NOT NULL,
  `dept_name` varchar(45) DEFAULT NULL,
  PRIMARY KEY (`did`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Dumping data for table `t_dept`
--

LOCK TABLES `t_dept` WRITE;
/*!40000 ALTER TABLE `t_dept` DISABLE KEYS */;
INSERT INTO `t_dept` VALUES (1,'开发组'),(2,'ai组'),(3,'运维组');
/*!40000 ALTER TABLE `t_dept` ENABLE KEYS */;
UNLOCK TABLES;

t_emp表:

DROP TABLE IF EXISTS `t_emp`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `t_emp` (
  `eid` int NOT NULL,
  `emo_name` varchar(45) DEFAULT NULL,
  `age` int DEFAULT NULL,
  `sex` char(1) DEFAULT NULL,
  `email` varchar(45) DEFAULT NULL,
  `did` int DEFAULT NULL,
  PRIMARY KEY (`eid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Dumping data for table `t_emp`
--

LOCK TABLES `t_emp` WRITE;
/*!40000 ALTER TABLE `t_emp` DISABLE KEYS */;
INSERT INTO `t_emp` VALUES (1,'lucy',23,'0','lucy@gmail.com',1),(2,'jack',24,'1','jack@gmail.com',1),(3,'smith',22,'1','smith@openai.com',2),(4,'zhangsan',46,'1','zhangsan@openai.com',2),(5,'limu',47,'1','limu@amazon.com',3),(6,'fong',23,'1','fong@amazon.com',3);
/*!40000 ALTER TABLE `t_emp` ENABLE KEYS */;
UNLOCK TABLES;
/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;

先大致看一下数据库中的数据:
如何在MyBatis中处理复杂结果集映射关系

  1. 建立mapper、pojo、映射文件
    整体的项目结构是:
    如何在MyBatis中处理复杂结果集映射关系
    mapper接口:
public interface DeptMapper {
}
public interface EmpMapper {
}

pojo:

// dept
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Dept{
    private Integer did;
    private String deptName;
}
// emp
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Emp {
    private Integer eid;
    private String empName;
    private Integer age;
    private String sex;
    private String email;
}

这里我直接使用lombok来动态的生成gettersetter方法
使用方法是直接在pom.xml文件中导入依赖

 <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
      <version>1.18.26</version>
    </dependency>

xxxMapper.xml

<!--DeptMapper.xml-->
<mapper namespace="com.fckey.mybatis.mapper.DeptMapper">
</mapper>
<!--EmpMapper.xml-->
<mapper namespace="com.fckey.mybatis.mapper.EmpMapper">
</mapper>

二、resultMap处理字段和属性的映射关系

若字段名和实体类中的属性名不一致,但是字段名和属性名通过驼峰规则可以可以进行转变的。或者是不能进行转变的。都有对应的处理方法。
下面这种就是符合驼峰规则的:
如何在MyBatis中处理复杂结果集映射关系
对于可以通过驼峰规则进行映射的,有一种特有的解决映射问题的方法,可以直接在mybatis-config.xml全局配置文件中配置mapUnderscoreToCamelCase支持这种关系的映射

 <settings>
        <setting name="mapUnderscoreToCamelCase" value="true"/>
    </settings>

还有更加通用的方法解决映射问题:

  1. 给所有查出的字段起一个别名
<!--    List<Emp> getAll();-->
    <select id="getAll" resultType="emp">
        select eid, emp_name empName, age, sex, email from t_emp
    </select>

  1. 自定义resultmap来定义映射规则
    resultMap中,一一对应地设置属性名->字段名,再在select标签中添加resultMap="对应resultMap的id"
<!--
        resultMap设置自定义映射关系
        id      唯一标识
        type    映射的实体类型

        子标签:id 设置主键的映射关系, result设置其他的映射关系
            property    设置映射关系中的属性名,必须是type属性所设置的实体类类型的属性名
            column      设置映射关系中的字段名,必须是sql语句查询出来的字段名

        如果使用resultMap,就所有属性都需要设置
-->
    <resultMap id="empResultMap" type="Emp">
        <id property="eid" column="eid"></id>
        <result property="empName" column="emp_name"></result>
        <result property="age" column="age"></result>
        <result property="sex" column="sex"></result>
        <result property="email" column="email"></result>
    </resultMap>

    <select id="getAll" resultMap="empResultMap">
        select * from t_emp
    </select>

三、多对一映射

如:查询员工信息以及员工所对应的部门信息

对于在Java实体类层面中维护多对多,一对多的这种映射关系。 需要在“一”的pojo中加入List<多>属性,在“多”的pojo中加入“一”
也就是说,在Dept类中,要加入private List<Emp> emps;在Emp类中,要加入private Dept dept;
如何在MyBatis中处理复杂结果集映射关系
下面我们来看看在mybatis中解决多对一映射关系是如何进行处理,以及处理方法有哪几种 ?

对于多对一关系中,对于SQL的查询,是固定的多表连接查询。这无论是对于哪个需要手写sql的orm框架,这步是少不了的。

 select * from t_emp left join t_dept
            on t_emp.eid = t_dept.did WHERE t_emp.eid = #{eid}

关键是,特定的orm框架如何处理映射关系,下面介绍MyBatis几种常见的处理映射的方法。
对于上文中,已经写了如果是字段有不一致的情况,可以使用resultmap的方式来解决。

0、级联方式处理映射关系

EmpMapper.xml中:

<!--    多对一映射关系,方式一:级联属性赋值-->
    <resultMap id="getEmpAndDeptResultMapOne" type="Emp">
        <id property="eid" column="eid"></id>
        <result property="empName" column="emp_name"></result>
        <result property="age" column="age"></result>
        <result property="sex" column="sex"></result>
        <result property="email" column="email"></result>
        <result property="dept.did" column="did"></result>
        <result property="dept.deptName" column="dept_name"></result>
    </resultMap>

<!--        Emp getEmpAndDept(@Param("eid") Integer eid);-->
    <select id="getEmpAndDept" resultMap="getEmpAndDeptResultMapOne">
        select * from t_emp left join t_dept
            on t_emp.eid = t_dept.did WHERE t_emp.eid = #{eid}
    </select>

notice:
IDEA可能会爆红,但是没有关系。
如何在MyBatis中处理复杂结果集映射关系

EmpMapper类中

public interface EmpMapper {
    /**
     * 查询员工及其所对应的部门信息
     */
    Emp getEmpAndDept(@Param("eid") Integer eid);
}

测试类中

    /**
     * 处理多对一的映射关系
     * a> 级联属性赋值
     * b> association
     * c> 分步查询
     */
    @Test
    public void testGetEmpAndDept(){
        SqlSession sqlSession = SqlSessionUtils.getSqlSession();
        EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
        Emp empAndDept = mapper.getEmpAndDept(1);
        System.out.println(empAndDept);
    }

如何在MyBatis中处理复杂结果集映射关系
最后,确实把dept给查出了。

1、使用association处理映射关系

这种处理映射关系的改变就是把需要处理多对一关系的单独使用association标签来定义了。
EmpMapper.xml

<resultMap id="empDeptMap" type="Emp">
    <id column="eid" property="eid"></id>
    <result column="ename" property="ename"></result>
    <result column="age" property="age"></result>
    <result column="sex" property="sex"></result>
    <association property="dept" javaType="Dept">
        <id column="did" property="did"></id>
        <result column="dname" property="dname"></result>
    </association>
</resultMap>
<!--Emp getEmpAndDeptByEid(@Param("eid") int eid);-->
<select id="getEmpAndDeptByEid" resultMap="empDeptMap">
    select emp.*,dept.* from t_emp emp left join t_dept dept on emp.did =
dept.did where emp.eid = #{eid}
</select>

结果依然和上面一样。

一般我们使用association来进行多对一的关系映射,这种比较形象。

2、分步查询解决多对一关系

对于上述的过程中,我们写的sql都是多表联查的SQL,给数据库发送的是一条查询请求。那我们能不能发送两条,然后将结果拼接?

(1) 查询员工信息

EmpMapper类中

public interface EmpMapper {
	/**
	* 通过分步查询查询员工信息 * @param eid
	* @return
	*/
	Emp getEmpByStep(@Param("eid") int eid);
}

EmpMapper.xml:

<!--    getEmpAndDeptByStepTwo是这条sql语句的全类名-->
    <resultMap id="getEmpAndDeptByStepResultMap" type="Emp">
        <id property="eid" column="eid"></id>
        <result property="empName" column="emp_name"></result>
        <result property="age" column="age"></result>
        <result property="sex" column="sex"></result>
        <result property="email" column="email"></result>
        <!--
                select: 设置分步查询的sql的唯一标识(namespace.SQLId或mapper接口的全类名.方法名)
                column:分步查询的条件
                fetchType: 当开启了全局的延迟记载后,可通过此属性手动控制延迟加载的效果
                fetchType:"lazy/eager" lazy表示延迟加载,eager表示立即加载
        -->
        <association property="dept"
                     select="com.fckey.mybatis.mapper.DeptMapper.getEmpAndDeptByStepTwo"
                     column="did"
                     fetchType="lazy">
        </association>
    </resultMap>

    <select id="getEmpByStep" resultMap="getEmpAndDeptByStepResultMap">
        select * from t_emp where eid = #{eid}
    </select>

(2) 根据员工所对应的部门id查询部门信息

DeptMapper接口:

public interface DeptMapper {
	/**
	* 分步查询的第二步:根据员工所对应的did查询部门信息
	*/
	Dept getEmpDeptByStep(@Param("did") int did);
}

DeptMapper.xml:

<!--        Dept getEmpAndDeptByStepTwo(Integer did);-->
<!--    分步查询可以实现懒加载-->
    <select id="getEmpAndDeptByStepTwo" resultType="Dept">
        select * from t_dept where did = #{did}
    </select>

直接来进行测试一下,发现

@Test
    public void testGetEmpByStep() throws IOException {
        SqlSession sqlSession = getSqlSession();
        EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
        Emp empByStep = mapper.getEmpByStep(1);
        System.out.println(empByStep);
    }

如何在MyBatis中处理复杂结果集映射关系

延迟加载

我们知道,对于分步查询,要是每次都发送两条查询语句可能就会造成时间上的损耗,但是,分步查询不是没有优点。
分步查询的优点:可以实现延迟加载,但是必须在核心配置文件中设置全局配置信息
第一种可以实现粗力度的设置方式,在全局配置文件mybatis-config.xml中:

  • lazyLoadingEnabled:延迟加载的全局开关。当开启时,所有关联对象都会延迟加载
  • aggressiveLazyLoading:当开启时,任何方法的调用都会加载该对象的所有属性。 否则,每个 属性会按需加载
    如何在MyBatis中处理复杂结果集映射关系
    此时就可以实现按需加载,获取的数据是什么,就只会执行相应的sql。此时可通过associationcollection中的fetchType属性设置当前的分步查询是否使用延迟加载,fetchType=“lazy(延迟加 载)|eager(立即加载)”.

假设,我现在设计一个场景,查询的就是一个员工的性别,这个没有涉及到对部门的查询。如果部门一起查出来了,说明是立即加载。反之,则是延迟加载。
延迟加载打开:
如何在MyBatis中处理复杂结果集映射关系
立即加载打开:
如何在MyBatis中处理复杂结果集映射关系
通过fetchType参数,可以手动控制延迟加载或立即加载,否则根据全局配置的属性决定是延迟加载还是立即加载。
如何在MyBatis中处理复杂结果集映射关系如何在MyBatis中处理复杂结果集映射关系

三、一对多的关系处理

需求:根据部门id查找部门以及部门中的员工信息

需要查询一对多、多对一的关系,需要在“一”的pojo中加入List<多>属性,在“多”的pojo中加入“一”。
也就是说,在Dept类中,要加入private List<Emp> emps;;在Emp类中,要加入private Dept dept;。然后给他们各自添加get、set方法,重写构造器和toString()

0、使用collection来维系一对多的关系

DeptMapper接口:

public interface DeptMapper {
    /*
    获取部门中所有的员工信息
     */
    Dept getDeptAndEmp(@Param("did") Integer did);
}

DeptMapper.xml

    <resultMap id="deptAndEmpResultMap" type="Dept">
        <id property="did" column="did"></id>
        <result property="deptName" column="dept_name"></result>
<!--
            collection:处理一对多的映射关系
            ofType:表示该属性对应的集合中存储数据的类型
-->
        <collection property="emps" ofType="Emp">
            <id property="eid" column="eid"></id>
            <result property="empName" column="emp_name"></result>
            <result property="age" column="age"></result>
            <result property="sex" column="sex"></result>
            <result property="email" column="email"></result>
        </collection>
    </resultMap>
<!--        Dept getDeptAndEmp(@Param("did") Integer did);-->
    <select id="getDeptAndEmp" resultMap="deptAndEmpResultMap">
        select * from t_dept left join t_emp on t_dept.did = t_emp.did where t_dept.did = #{did}
    </select>

测试类来进行测试;

  @Test
    public void testGetDeptAndEmp() throws IOException {
        SqlSession sqlSession = getSqlSession();
        DeptMapper mapper = sqlSession.getMapper(DeptMapper.class);
        Dept dept = mapper.getDeptAndEmp(1);
        System.out.println(dept.getDeptName());
        dept.getEmps().forEach(System.out::println);
    }

最后结果得出;
如何在MyBatis中处理复杂结果集映射关系

1、分步查询

在处理一对多的关系中,也有分布查询,在分步查询中也有延迟加载立即加载两种。

(1)查询部门信息

DeptMapper接口

public interface DeptMapper {
    /**
     * 分步查询 查询部门及其所有的员工信息
     * 第一步  查询部门信息
     */
    Dept getDeptAndEmoByStepOne(@Param("did") Integer did);
}

DeptMapper.xml

   <!--    分步查询-->
    <resultMap id="deptAndEmoByStepOneMap" type="Dept">
        <id property="did" column="did"></id>
        <result property="deptName" column="dept_name"></result>
        <collection property="emps"
                    select="com.fckey.mybatis.mapper.EmpMapper.getDeptAndEmpByStepTwo"
                    column="did"
                    fetchType="lazy"
        >
        </collection>
    </resultMap>
    <!--        Dept getDeptAndEmoByStepOne(@Param("did") Integer did);-->
    <select id="getDeptAndEmoByStepOne" resultMap="deptAndEmoByStepOneMap">
        select * from t_dept where did = #{did}
    </select>

(2)根据部门id查询部门中的所有员工

EmpMapper

public interface EmpMapper {
    /**
     * 分步查询 查询部门及其所有的员工信息
     * 第一步  查询部门信息
     * 第二步  根据查询员工信息
     */
    List<Emp> getDeptAndEmpByStepTwo(@Param("did") Integer did);
}

EmpMapper.xml

<!--    分步查询-->
<!--    List<Emp> getDeptAndEmpByStepTwo(@Param("did") Integer did);-->
    <select id="getDeptAndEmpByStepTwo" resultType="Emp">
        select * from t_emp where did = #{did}
    </select>

(3)测试类

  @Test
    public void testGetDeptAndEmp() throws IOException {
        SqlSession sqlSession = getSqlSession();
        DeptMapper mapper = sqlSession.getMapper(DeptMapper.class);
        Dept dept = mapper.getDeptAndEmp(1);
        System.out.println(dept.getDeptName());
        System.out.println("====================");
        dept.getEmps().forEach(System.out::println);
    }

然后,设置的是延迟加载的模式,运行结果如下所示
如何在MyBatis中处理复杂结果集映射关系


然后,有人问,有一对多,多对一,那多对多的关系呢?对于多对多的关系需要抽离出第三张表,本质上还是一对多,多对一的变体。文章来源地址https://www.toymoban.com/news/detail-454024.html

到了这里,关于如何在MyBatis中处理复杂结果集映射关系的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Mybatis中的关系映射

    目录 前言 1.一对一的映射关系 1.1 创建模型类和Vo类  1.2 配置当前模型类的mapper.xml 1.3 开始测试 2.一对多的映射关系 2.1 创建模型类和Vo类 2.2 配置当前模型类的mapper.xml 2.3 开始测试 3.多对多的映射关系 总结  注意点:  一对一映射(One-to-One Mapping) : 一对一关系指的是两个

    2024年02月09日
    浏览(38)
  • MyBatis关联关系映射详解

    目录 前言 一、 什么是关联关系映射? 二、MyBatis的关系映射方式 1.基于XML配置的关系映射 2.基于注解的关系映射 三、如何使用MyBatis进行关系映射? 四、关于关系映射的一些建议 五、关联关系映射 1.一对一关联关系映射 嵌套查询 嵌套结果映射 2.一对多关联关系映射 嵌套查

    2024年02月09日
    浏览(64)
  • MyBatis进阶:掌握MyBatis动态SQL与模糊查询、结果映射,让你在面试中脱颖而出!!

    目录 一、引言 二、MyBatis动态SQL 2.1.if元素使用 2.2.foreach元素使用 三、MyBatis模糊查询 ①使用#{字段名} ②使用${字段名} ③使用concat{\\\'%\\\',#{字段名},\\\'%\\\'} 总结 四、MyBatis结果映射 4.1.案例演示 4.1.1.resultType进行结果映射 4.1.2.resultMap进行结果映射 在当今的软件开发环境中,数据库的使

    2024年02月11日
    浏览(46)
  • 认识Mybatis的关联关系映射,灵活关联表对象之间的关系

    目录      一、概述 ( 1 )  介绍 ( 2 )  关联关系映射 ( 3 ) 关联讲述 二、一对一关联映射 2.1 数据库创建 2.2 配置文件  2.3 代码生成 2.4 编写测试 三、一对多关联映射 四 、多对多关联映射 给我们带来的收获 关联关系映射是指在数据库中,通过定义 表之间的关联关系 ,将多

    2024年02月11日
    浏览(46)
  • 【MyBatis】自定义resultMap三种映射关系

    目录 一、一对一映射(One-to-One) 1.1 表关系 1.2 resultMap设置自定义映射  二、一对多映射(One-to-Many) 2.1 创建实体 2.2 级联方式处理映射关系 2.3 定义SQL 2.4 OrderMapper接口 2.5 编写业务逻辑层 2.6 Junit测试 三、多对多映射(Many-to-Many) 3.1 表关系 3.2 创建实体 3.3 处理映射关系、

    2024年02月10日
    浏览(47)
  • MyBatis:生命周期、作用域、结果集映射 ResultMap、日志、分页、使用注解开发、Lombok

    理解不同 作用域 和 生命周期 类别是至关重要的,因为错误的使用会导致非常严重的 并发问题 。 SqlSessionFactoryBuilder 一旦创建了 SqlSessionFactory,就不再需要它了; 最佳作用域 是方法作用域(也就是局部方法变量)。 SqlSessionFactory :相当于 数据库连接池 一旦被创建就应该在

    2024年02月02日
    浏览(56)
  • MyBatis中至关重要的关系映射----全方面介绍

    目录 一 对于映射的概念 1.1 三种关系映射 1.2 resultType与resultMap的区别 resultType: resultMap: 二,一对一关联查询 2.1 嵌套结果集编写 2.2 案例演示 三,一对多关联查询 3.1 嵌套结果集编写  3.3 案例演示 四,多对多关联查询  4.1 嵌套结果集编写  4.2 案例演示      在关系型数

    2024年02月09日
    浏览(39)
  • MyBatis注解开发---实现自定义映射关系和关联查询

    目录 相关导读 一、使用注解实现自定义映射关系 1. 编写注解方法 2. 编写测试方法

    2023年04月09日
    浏览(44)
  • Mybatis的三种映射关系以及联表查询

    目录 一、概念 二、一对一 1、配置generatorConfig.xml 2、Vo包的编写 3、xml的sql编写 4、编写对应接口及实现类 5、测试 三、一对多 1、Vo包类的编写 2、xml的sql编写 3、编写对应接口及实现类 4、测试 四、多对多 1、Vo类 2、xml的sql配置 3、接口及接口实现类 4、测试 1、MyBatis中表之间

    2024年02月10日
    浏览(48)
  • Mybatis学习笔记,包含mybatis基本使用、关系映射、动态SQL、分页插件等等

    😀😀😀创作不易,各位看官点赞收藏. 简介:MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain

    2024年02月15日
    浏览(49)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包