【MyBatis】映射一对多和多对多关系配置

本文涉及的产品
服务治理 MSE Sentinel/OpenSergo,Agent数量 不受限
可观测可视化 Grafana 版,10个用户账号 1个月
简介: resultMap 允许我们定义复杂的映射规则,将结果集中的多个字段映射到一个对象中。因为我们是一对多的所以我们再编写vo类的时候,里面是使用list集合。建立我们给的sql文件,运行它用这里面的表,让我们更好的示例操作。在我们的配置文件里面配置我们需要的几个表,自动生成所需文件。当然我们要先建立这个包里面的类才能更好的下一步。在原本的基础的sql上我们增加一个一对多的sql。在上面我们已经写好了sql,我们生成对应的。在我们的里面添加一个sql的方法编写。在生成的接口类里面编写对应的接口方法。


一、概念

1、MyBatis中表之间的关系是如何映射的处理的?

resultType:使用多表查询我们经常会resultType="java.utils.Map" ,我们不推荐这样写,但是这样写对自己比较有利。

    1. 好处:resultType 是直接将查询结果映射到 Java 对象,可以使用简单的类型(如 int、String)或复杂的自定义类型。它的好处是简单直观,易于使用。
    2. 弊端:对于复杂的关系映射,resultType 可能会变得冗长,并且无法处理一对多或多对多的关系映射。

    resultMap:resultMap 允许我们定义复杂的映射规则,将结果集中的多个字段映射到一个对象中。

      1. 好处:可以处理复杂的关系映射,支持一对多或多对多的关系映射。我们可以在 resultMap 中定义映射规则,指定字段与属性间的映射关系,并通过嵌套 resultMap 处理表之间的关系。
      2. 弊端:相对于 resultType,resultMap 的配置较为繁琐。

      二、一对一

      文件配置查看这篇spring整合mybatis教程(详细易懂)里面有配置文件

      1、建表

      建立我们给的sql文件,运行它用这里面的表,让我们更好的示例操作。

      运行会有以下这几个表

      image.gif编辑

      【ps】当然可以用自己的表文件进行操作

      2、配置generatorConfig.xml

      在我们的配置文件里面配置我们需要的几个表,自动生成所需文件

      <table schema="" tableName="t_hibernate_book" domainObjectName="HBook"
                     enableCountByExample="false" enableDeleteByExample="false"
                     enableSelectByExample="false" enableUpdateByExample="false">
              </table>
              <table schema="" tableName="t_hibernate_book_category" domainObjectName="HBookCategory"
                     enableCountByExample="false" enableDeleteByExample="false"
                     enableSelectByExample="false" enableUpdateByExample="false">
              </table>
              <table schema="" tableName="t_hibernate_category" domainObjectName="HCategory"
                     enableCountByExample="false" enableDeleteByExample="false"
                     enableSelectByExample="false" enableUpdateByExample="false">
              </table>
              <table schema="" tableName="t_hibernate_order" domainObjectName="HOrder"
                     enableCountByExample="false" enableDeleteByExample="false"
                     enableSelectByExample="false" enableUpdateByExample="false">
              </table>
              <table schema="" tableName="t_hibernate_order_item" domainObjectName="HOrderItem"
                     enableCountByExample="false" enableDeleteByExample="false"
                     enableSelectByExample="false" enableUpdateByExample="false">
              </table>
      image.gif

      3、生成Moder和Mapper

        1. 选中Maven
        2. 选择自己的项目工程
        3. 选择插件
        4. 选择mybatis-generator
        5. 双击mybatis-generator:generate【注意】不要连续双击,会出问题

        image.gif编辑

        后面会生成我们配置的文件等文件 image.gif编辑

        5、Tostring

        在你生成的类里面添加@ToString

        image.gif编辑

        image.gif编辑

        6、Vo包的编写

        当然我们要先建立这个包里面的类才能更好的下一步。

        我们现在示例的是一对一的,所以根据前面以此类推我们建立一个HOrderItemVo类

        package com.tgq.vo;
        import com.tgq.model.HOrder;
        import com.tgq.model.HOrderItem;
        /**
         * @软件包名 com.tgq.vo
         * @用户 tgq
         * @create 2023-08-26 下午4:37
         * @注释说明:
         */
        public class HOrderItemVo extends HOrderItem {
            private HOrder hOrder;
            public HOrder gethOrder() {
                return hOrder;
            }
            public void sethOrder(HOrder hOrder) {
                this.hOrder = hOrder;
            }
        }
        image.gif

        7、xml的sql编写

        在我们的里面添加一个sql的方法编写

        <resultMap id="HOrderItemVoMap" type="com.tgq.vo.HOrderItemVo">
                <result column="order_itemId" property="orderItemId"/>
                <result column="product_id" property="productId"/>
                <result column="quantity" property="quantity"/>
                <result column="oid" property="oid"/>
                <!--association是一对一的关系-->
                <association property="hOrder" javaType="com.tgq.model.HOrder">
                    <result column="order_id" property="orderId"/>
                    <result column="order_no" property="orderNo"/>
                </association>
            </resultMap>
            <select id="selectByHOrderId" resultMap="HOrderItemVoMap" parameterType="java.lang.Integer">
                select *
                from t_hibernate_order o,
                     t_hibernate_order_item oi
                where o.order_id = oi.oid
                  and oi.order_item_id = #{oiid}
            </select>
        image.gif

         

        8、编写对应接口及实现类

        在上面我们已经写好了sql,我们生成对应的接口接口实现方法。

        在我们生成的HOrderItemMapper 接口里面编写

        package com.tgq.mapper;
        import com.tgq.model.HOrderItem;
        import com.tgq.vo.HOrderItemVo;
        import org.apache.ibatis.annotations.Param;
        import org.springframework.stereotype.Repository;
        @Repository
        public interface HOrderItemMapper {
            int deleteByPrimaryKey(Integer orderItemId);
            int insert(HOrderItem record);
            int insertSelective(HOrderItem record);
            HOrderItem selectByPrimaryKey(Integer orderItemId);
            int updateByPrimaryKeySelective(HOrderItem record);
            int updateByPrimaryKey(HOrderItem record);
            HOrderItemVo selectByHOrderId(@Param("oiid") Integer oiid);
        }
        image.gif

        创建一个biz的包,里面编写一个HOrderItemBiz接口类并且编写接口方法

        package com.tgq.biz;
        import com.tgq.vo.HOrderItemVo;
        /**
         * @软件包名 com.tgq.biz
         * @用户 tgq
         * @create 2023-08-26 下午4:48
         * @注释说明:
         */
        public interface HOrderItemBiz {
            HOrderItemVo selectByHOrderId(Integer oiid);
        }
        image.gif

        在这个biz里面新建一个impl包,里面创建一个HOrderItemBizImpl 接口实现类,继承HOrderItemBiz

        package com.tgq.biz.impl;
        import com.tgq.biz.HOrderItemBiz;
        import com.tgq.mapper.HOrderItemMapper;
        import com.tgq.vo.HOrderItemVo;
        import org.springframework.beans.factory.annotation.Autowired;
        import org.springframework.stereotype.Service;
        /**
         * @软件包名 com.tgq.biz.impl
         * @用户 tgq
         * @create 2023-08-26 下午4:48
         * @注释说明:
         */
        @Service
        public class HOrderItemBizImpl implements HOrderItemBiz {
            @Autowired
            private HOrderItemMapper hOrderItemMapper;
            @Override
            public HOrderItemVo selectByHOrderId(Integer oiid) {
                return hOrderItemMapper.selectByHOrderId(oiid);
            }
        }
        image.gif

        9、测试

        在这个接口实现类里面创建一个测试类

        image.gif编辑

         

        package com.tgq.biz.impl;
        import com.tgq.biz.HOrderItemBiz;
        import com.tgq.vo.HOrderItemVo;
        import org.junit.Test;
        import org.junit.runner.RunWith;
        import org.springframework.beans.factory.annotation.Autowired;
        import org.springframework.test.context.ContextConfiguration;
        import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
        /**
         * @软件包名 com.tgq.biz.impl
         * @用户 tgq
         * @create 2023-08-26 下午4:58
         * @注释说明:
         */
        @RunWith(SpringJUnit4ClassRunner.class)
        @ContextConfiguration(locations = {"classpath:spring-context.xml"})
        public class HOrderItemBizImplTest {
            @Autowired
            private HOrderItemBiz hOrderItemBiz;
            @Test
            public void selectByHOrderId() {
                HOrderItemVo hOrderItemVo = hOrderItemBiz.selectByHOrderId(27);
                System.out.println(hOrderItemVo);
            }
        }
        image.gif

        运行结果image.gif编辑

        三、一对多

        1、Vo包类的编写

        因为我们是一对多的所以我们再编写vo类的时候,里面是使用list集合

        package com.tgq.vo;
        import com.tgq.model.HOrder;
        import com.tgq.model.HOrderItem;
        import java.util.ArrayList;
        import java.util.List;
        /**
         * @软件包名 com.tgq.vo
         * @用户 tgq
         * @create 2023-08-26 下午3:55
         * @注释说明:
         */
        public class HOrderVo extends HOrder {
            //    一个订单存在多个订单项
            private List<HOrderItem> hOrderItems = new ArrayList<>();
            public List<HOrderItem> gethOrderItems() {
                return hOrderItems;
            }
            public void sethOrderItems(List<HOrderItem> hOrderItems) {
                this.hOrderItems = hOrderItems;
            }
        }

        image.gif

        2、xml的sql编写

        在原本的基础的sql上我们增加一个一对多的sql

        <!--  resultType="com.tgq.vo.HOrderVo" 在多表的字段是无法使用的-->
            <!--  我们要写一个resultMap映射-->
            <resultMap id="HOrderVoMap" type="com.tgq.vo.HOrderVo">
                <!--   每个订单对应的属性,column:数据库属性名;property:实体类属性名     -->
                <result column="order_id" property="orderId"/>
                <result column="order_no" property="orderNo"/>
                <!--   我们设置hOrderItems数组里面的属性     -->
                <!--   collection是一对多的关系     -->
                <collection property="hOrderItems" ofType="com.tgq.model.HOrderItem">
                    <result column="order_itemId" property="orderItemId"/>
                    <result column="product_id" property="productId"/>
                    <result column="quantity" property="quantity"/>
                    <result column="oid" property="oid"/>
                </collection>
            </resultMap>
            <select id="byOid" resultMap="HOrderVoMap" parameterType="java.lang.Integer">
                select *
                from t_hibernate_order o,
                     t_hibernate_order_item oi
                where o.order_id = oi.oid
                  and o.order_id = #{oid}
            </select>

        image.gif

        3、编写对应接口及实现类

        根据sql生成的对应的HOrderMapper 类里面生成已经编写好的sql方法

        package com.tgq.mapper;
        import com.tgq.model.HOrder;
        import com.tgq.vo.HOrderVo;
        import org.apache.ibatis.annotations.Param;
        import org.springframework.stereotype.Repository;
        @Repository
        public interface HOrderMapper {
            int deleteByPrimaryKey(Integer orderId);
            int insert(HOrder record);
            int insertSelective(HOrder record);
            HOrder selectByPrimaryKey(Integer orderId);
            int updateByPrimaryKeySelective(HOrder record);
            int updateByPrimaryKey(HOrder record);
            //============================================
            HOrderVo byOid(@Param("oid") Integer oid);
        }

        image.gif

        biz包里面新建一个接口HOrderBiz

        package com.tgq.biz;
        import com.tgq.vo.HOrderVo;
        /**
         * @软件包名 com.tgq.biz
         * @用户 tgq
         * @create 2023-08-26 下午4:15
         * @注释说明:
         */
        public interface HOrderBiz {
            HOrderVo byOid(Integer oid);
        }

        image.gif

        biz包里面的impl里面新建一个Java类实现HOrderBiz 接口

        package com.tgq.biz.impl;
        import com.tgq.biz.HOrderBiz;
        import com.tgq.mapper.HOrderMapper;
        import com.tgq.vo.HOrderVo;
        import org.springframework.beans.factory.annotation.Autowired;
        import org.springframework.stereotype.Service;
        /**
         * @软件包名 com.tgq.biz.impl
         * @用户 tgq
         * @create 2023-08-26 下午4:16
         * @注释说明:
         */
        @Service
        public class HOrderBizImpl implements HOrderBiz {
            @Autowired
            private HOrderMapper hOrderMapper;
            @Override
            public HOrderVo byOid(Integer oid) {
                return hOrderMapper.byOid(oid);
            }
        }

        image.gif

        4、测试

        我们新建一个测试类进行编写的方法进行测试

        package com.tgq.biz.impl;
        import com.tgq.biz.HOrderBiz;
        import com.tgq.vo.HOrderVo;
        import org.junit.After;
        import org.junit.Before;
        import org.junit.Test;
        import org.junit.runner.RunWith;
        import org.springframework.beans.factory.annotation.Autowired;
        import org.springframework.test.context.ContextConfiguration;
        import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
        import static org.junit.Assert.*;
        /**
         * @软件包名 com.tgq.biz.impl
         * @用户 tgq
         * @create 2023-08-26 下午4:22
         * @注释说明:
         */
        @RunWith(SpringJUnit4ClassRunner.class)
        @ContextConfiguration(locations = {"classpath:spring-context.xml"})
        public class HOrderBizImplTest {
            @Autowired
            private HOrderBiz hOrderBiz;
            @Test
            public void byOid() {
                HOrderVo hOrderVo = hOrderBiz.byOid(7);
                System.out.println(hOrderVo);
            }
        }

        image.gif

        测试结果

        image.gif编辑

        四、多对多

        1、Vo类

        package com.tgq.vo;
        import com.tgq.model.HBook;
        import com.tgq.model.HCategory;
        import java.util.List;
        /**
         * @软件包名 com.tgq.vo
         * @用户 tgq
         * @create 2023-08-27 下午10:29
         * @注释说明:
         */
        public class HBookVo extends HBook {
            private List<HCategory> hCategoryList;
            public List<HCategory> gethCategoryList() {
                return hCategoryList;
            }
            public void sethCategoryList(List<HCategory> hCategoryList) {
                this.hCategoryList = hCategoryList;
            }
        }

        image.gif

        package com.tgq.vo;
        import com.tgq.model.HBook;
        import com.tgq.model.HCategory;
        import java.util.ArrayList;
        import java.util.List;
        /**
         * @软件包名 com.tgq.vo
         * @用户 tgq
         * @create 2023-08-27 下午11:03
         * @注释说明:
         */
        public class HCategoryVo extends HCategory {
            private List<HBook> hBooks = new ArrayList<>();
            public List<HBook> gethBooks() {
                return hBooks;
            }
            public void sethBooks(List<HBook> hBooks) {
                this.hBooks = hBooks;
            }
        }

        image.gif

        2、xml的sql配置

        分别在不同的xml配置文件里面配置

        <resultMap id="HBookVo" type="com.tgq.vo.HBookVo">
                <result column="book_id" property="bookId"/>
                <result column="book_name" property="bookName"/>
                <result column="price" property="price"/>
                <collection property="hCategoryList" ofType="com.tgq.model.HCategory">
                    <result column="category_id" property="categoryId"/>
                    <result column="category_name" property="categoryName"/>
                </collection>
            </resultMap>
            <!--    根据书籍id查询出书籍信息及所属类别-->
            <select id="selectByBId" resultMap="HBookVo" parameterType="java.lang.Integer">
                select *
                from t_hibernate_book b,
                     t_hibernate_book_category bc,
                     t_hibernate_category c
                where b.book_id = bc.bid
                  and bc.cid = c.category_id
                  and b.book_id = #{bid}
            </select>

        image.gif

        <resultMap id="HCategoryVo" type="com.tgq.vo.HCategoryVo">
                <result column="category_id" property="categoryId"/>
                <result column="category_name" property="categoryName"/>
                <collection property="hBooks" ofType="com.tgq.model.HBook">
                    <result column="book_id" property="bookId"/>
                    <result column="book_name" property="bookName"/>
                    <result column="price" property="price"/>
                </collection>
            </resultMap>
            <select id="selectByCId" resultMap="HCategoryVo" parameterType="java.lang.Integer">
                select *
                from t_hibernate_book b,
                     t_hibernate_book_category bc,
                     t_hibernate_category c
                where b.book_id = bc.bid
                  and bc.cid = c.category_id
                  and c.category_id = #{cid}
            </select>

        image.gif

        3、接口及接口实现类

        在生成的接口类里面编写对应的接口方法

        package com.tgq.mapper;
        import com.tgq.model.HBook;
        import com.tgq.vo.HBookVo;
        import org.apache.ibatis.annotations.Param;
        public interface HBookMapper {
            int deleteByPrimaryKey(Integer bookId);
            int insert(HBook record);
            int insertSelective(HBook record);
            HBook selectByPrimaryKey(Integer bookId);
            int updateByPrimaryKeySelective(HBook record);
            int updateByPrimaryKey(HBook record);
            HBookVo selectByBId(@Param("bid") Integer bid);
        }

        image.gif

        package com.tgq.mapper;
        import com.tgq.model.HCategory;
        import com.tgq.vo.HCategoryVo;
        import org.apache.ibatis.annotations.Param;
        import org.springframework.stereotype.Repository;
        @Repository
        public interface HCategoryMapper {
            int deleteByPrimaryKey(Integer categoryId);
            int insert(HCategory record);
            int insertSelective(HCategory record);
            HCategory selectByPrimaryKey(Integer categoryId);
            int updateByPrimaryKeySelective(HCategory record);
            int updateByPrimaryKey(HCategory record);
            HCategoryVo selectByCId(@Param("cid") Integer cid);
        }

        image.gif

        biz包里面新建一个HBookBiz接口类

        package com.tgq.biz;
        import com.tgq.vo.HBookVo;
        /**
         * @软件包名 com.tgq.biz
         * @用户 tgq
         * @create 2023-08-27 下午10:50
         * @注释说明:
         */
        public interface HBookBiz {
            HBookVo selectByBId(Integer bid);
        }

        image.gif

        package com.tgq.biz;
        import com.tgq.vo.HCategoryVo;
        public interface HCategoryBiz {
            HCategoryVo selectByCId(Integer cid);
        }

        image.gif

        Biz里面的impl包里面新建HBookBizImpl 接口实现HBookBiz接口类

        package com.tgq.biz.impl;
        import com.tgq.biz.HBookBiz;
        import com.tgq.mapper.HBookMapper;
        import com.tgq.vo.HBookVo;
        import org.springframework.beans.factory.annotation.Autowired;
        import org.springframework.stereotype.Service;
        /**
         * @软件包名 com.tgq.biz.impl
         * @用户 tgq
         * @create 2023-08-27 下午10:53
         * @注释说明:
         */
        @Service
        public class HBookBizImpl implements HBookBiz {
            @Autowired
            private HBookMapper hBookMapper;
            @Override
            public HBookVo selectByBId(Integer bid) {
                return hBookMapper.selectByBId(bid);
            }
        }

        image.gif

        package com.tgq.biz.impl;
        import com.tgq.biz.HCategoryBiz;
        import com.tgq.mapper.HCategoryMapper;
        import com.tgq.vo.HCategoryVo;
        import org.springframework.beans.factory.annotation.Autowired;
        import org.springframework.stereotype.Service;
        /**
         * @软件包名 com.tgq.biz.impl
         * @用户 tgq
         * @create 2023-08-27 下午11:12
         * @注释说明:
         */
        @Service
        public class HCategoryBizImpl implements HCategoryBiz {
            @Autowired
            private HCategoryMapper hCategoryMapper;
            @Override
            public HCategoryVo selectByCId(Integer cid) {
                return hCategoryMapper.selectByCId(cid);
            }
        }

        image.gif

        4、测试

        建立一个测试类

        package com.tgq.biz.impl;
        import com.tgq.biz.HBookBiz;
        import com.tgq.vo.HBookVo;
        import org.junit.Test;
        import org.junit.runner.RunWith;
        import org.springframework.beans.factory.annotation.Autowired;
        import org.springframework.test.context.ContextConfiguration;
        import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
        import static org.junit.Assert.*;
        /**
         * @软件包名 com.tgq.biz.impl
         * @用户 tgq
         * @create 2023-08-27 下午10:59
         * @注释说明:
         */
        @RunWith(SpringJUnit4ClassRunner.class)
        @ContextConfiguration(locations = {"classpath:spring-context.xml"})
        public class HBookBizImplTest {
            @Autowired
            private HBookBiz hBookBiz;
            @Test
            public void selectByBId() {
                HBookVo hBookVo = this.hBookBiz.selectByBId(8);
                System.out.println(hBookVo);
            }
        }

        image.gif

        package com.tgq.biz.impl;
        import com.tgq.biz.HCategoryBiz;
        import com.tgq.vo.HCategoryVo;
        import org.junit.Test;
        import org.junit.runner.RunWith;
        import org.springframework.beans.factory.annotation.Autowired;
        import org.springframework.test.context.ContextConfiguration;
        import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
        import static org.junit.Assert.*;
        /**
         * @软件包名 com.tgq.biz.impl
         * @用户 tgq
         * @create 2023-08-27 下午11:14
         * @注释说明:
         */
        @RunWith(SpringJUnit4ClassRunner.class)
        @ContextConfiguration(locations = {"classpath:spring-context.xml"})
        public class HCategoryBizImplTest {
            @Autowired
            private HCategoryBiz hCategoryBiz;
            @Test
            public void selectByCId(){
                HCategoryVo hCategoryVo = hCategoryBiz.selectByCId(8);
                System.out.println(hCategoryVo);
                hCategoryVo.gethBooks().forEach(System.out::println);
            }
        }

        image.gif

        测试结果

        image.gif编辑

        image.gif编辑


        相关文章
        |
        30天前
        |
        SQL 安全 BI
        基于jeecg-boot的nbcio-boot因升级mybatis-plus到3.5.3.1和JSQLParser 到4.6而引起的在线报表配置报错处理
        基于jeecg-boot的nbcio-boot因升级mybatis-plus到3.5.3.1和JSQLParser 到4.6而引起的在线报表配置报错处理
        37 0
        |
        30天前
        |
        SQL 缓存 Java
        mybatis 一对多查询
        mybatis 一对多查询
        31 0
        |
        18天前
        |
        XML Java 数据库连接
        【MyBatisPlus】快速入门、常用注解、常用配置
        【MyBatisPlus】快速入门、常用注解、常用配置
        18 0
        |
        20天前
        |
        算法 BI 数据库
        MyBatisPlus查询条件设置、映射匹配兼容性、id生成策略、多数据操作
        MyBatisPlus查询条件设置、映射匹配兼容性、id生成策略、多数据操作
        32 3
        |
        30天前
        |
        Java 数据库连接 mybatis
        mybatis的一对多
        mybatis的一对多
        |
        30天前
        |
        SQL Java 数据库连接
        15:MyBatis对象关系与映射结构-Java Spring
        15:MyBatis对象关系与映射结构-Java Spring
        42 4
        |
        30天前
        |
        SQL Java 数据库连接
        【Mybatis】深入学习MyBatis:概述、主要特性以及配置与映射
        【Mybatis】深入学习MyBatis:概述、主要特性以及配置与映射
        【Mybatis】深入学习MyBatis:概述、主要特性以及配置与映射
        |
        30天前
        |
        SQL Java 数据库连接
        挺详细的spring+springmvc+mybatis配置整合|含源代码
        挺详细的spring+springmvc+mybatis配置整合|含源代码
        211 1
        |
        27天前
        |
        算法 Java 数据库连接
        Spring+MySQL+数据结构+集合,Alibaba珍藏版mybatis手写文档
        Spring+MySQL+数据结构+集合,Alibaba珍藏版mybatis手写文档
        |
        30天前
        |
        Java 数据库连接 Spring
        Spring 整合mybatis
        Spring 整合mybatis
        26 2