Mybatis的关联关系映射以及自定义resultMap三种映射关系

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS PostgreSQL,集群系列 2核4GB
简介: Mybatis的关联关系映射以及自定义resultMap三种映射关系

前言:

今天我们来学习Mybatis的关联关系映射以及自定义resultMap三种映射关系,希望这篇博客可以帮助大家的学习工作!!!

 

经典面试题:

问 :在Mybatis中的表之间的关系是如何映射处理的?

答:

在MyBatis中,表与表之间的关系主要通过两种方式进行映射:一对一(One-to-One)和一对多(One-to-Many)关系。

对于一对一关系,可以使用两个表之间的外键进行映射。在MyBatis的映射文件中,可以使用<resultMap>标签定义一个结果映射对象,并使用<association>标签进行关联映射。

对于一对多关系,可以使用一个表的外键与另一个表的主键进行映射。在MyBatis的映射文件中,可以使用<resultMap>标签定义一个结果映射对象,并使用<collection>标签进行集合映射。

需要注意的是,在映射文件中,可以使用<resultMap>标签来定义表字段与Java对象属性之间的映射关系。

准备:将具有一对一,一对多的表导入mysqll数据库中去。

一,关联关系映射

关联关系映射在Mybatis中主要通过三种方式实现:一对一关联和一对多关联及多对多关联。

一,一对一

例如:一个用户(User)与一个地址(Address)之间的关系。

二,一对多

例如: 订单表的id对应多个订单详情表

三,多对多

例如:一本书对应多种类型,一种类型对应多本书

二,具体步骤:

一,一对一

2.1创建名为 t_hibernate_book (书籍表) 数据表

创建名为 t_hibernate_book_category (书籍类别表) 数据表

其中名为 bid 的属性字段为 t_hibernate_book (书籍表) 的 bid(主键) 的外键

其中名为 cid 的属性字段为 t_hibernate_category (类别表) 的 category_id (主键) 的外键

创建名为 t_hibernate_category (类别表) 数据表

 

t_hibernate_order (订单表) 数据表

t_hibernate_order_item (订单详情表) 数据表

修改 generatorConfig.xml 的配置文件

 

代码:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE generatorConfiguration PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
        "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd" >
<generatorConfiguration>
    <!-- 引入配置文件 -->
    <properties resource="jdbc.properties"/>
    <!--指定数据库jdbc驱动jar包的位置-->
    <classPathEntry location="D:\\temp\\mvn_repository\\mysql\\mysql-connector-java\\5.1.44\\mysql-connector-java-5.1.44.jar"/>
    <!-- 一个数据库一个context -->
    <context id="infoGuardian">
        <!-- 注释 -->
        <commentGenerator>
            <property name="suppressAllComments" value="true"/><!-- 是否取消注释 -->
            <property name="suppressDate" value="true"/> <!-- 是否生成注释代时间戳 -->
        </commentGenerator>
        <!-- jdbc连接 -->
        <jdbcConnection driverClass="${jdbc.driver}"
                        connectionURL="${jdbc.url}" userId="${jdbc.username}" password="${jdbc.password}"/>
        <!-- 类型转换 -->
        <javaTypeResolver>
            <!-- 是否使用bigDecimal, false可自动转化以下类型(Long, Integer, Short, etc.) -->
            <property name="forceBigDecimals" value="false"/>
        </javaTypeResolver>
        <!-- 01 指定javaBean生成的位置 -->
        <!-- targetPackage:指定生成的model生成所在的包名 -->
        <!-- targetProject:指定在该项目下所在的路径  -->
        <javaModelGenerator targetPackage="com.CloudJun.model"
                            targetProject="src/main/java">
            <!-- 是否允许子包,即targetPackage.schemaName.tableName -->
            <property name="enableSubPackages" value="false"/>
            <!-- 是否对model添加构造函数 -->
            <property name="constructorBased" value="true"/>
            <!-- 是否针对string类型的字段在set的时候进行trim调用 -->
            <property name="trimStrings" value="false"/>
            <!-- 建立的Model对象是否 不可改变  即生成的Model对象不会有 setter方法,只有构造方法 -->
            <property name="immutable" value="false"/>
        </javaModelGenerator>
        <!-- 02 指定sql映射文件生成的位置 -->
        <sqlMapGenerator targetPackage="com.CloudJun.mapper"
                         targetProject="src/main/java">
            <!-- 是否允许子包,即targetPackage.schemaName.tableName -->
            <property name="enableSubPackages" value="false"/>
        </sqlMapGenerator>
        <!-- 03 生成XxxMapper接口 -->
        <!-- type="ANNOTATEDMAPPER",生成Java Model 和基于注解的Mapper对象 -->
        <!-- type="MIXEDMAPPER",生成基于注解的Java Model 和相应的Mapper对象 -->
        <!-- type="XMLMAPPER",生成SQLMap XML文件和独立的Mapper接口 -->
        <javaClientGenerator targetPackage="com.CloudJun.mapper"
                             targetProject="src/main/java" type="XMLMAPPER">
            <!-- 是否在当前路径下新加一层schema,false路径com.oop.eksp.user.model, true:com.oop.eksp.user.model.[schemaName] -->
            <property name="enableSubPackages" value="false"/>
        </javaClientGenerator>
        <!-- 配置表信息 -->
        <!-- schema即为数据库名 -->
        <!-- tableName为对应的数据库表 -->
        <!-- domainObjectName是要生成的实体类 -->
        <!-- enable*ByExample是否生成 example类 -->
        <!--<table schema="" tableName="t_book" domainObjectName="Book"-->
        <!--enableCountByExample="false" enableDeleteByExample="false"-->
        <!--enableSelectByExample="false" enableUpdateByExample="false">-->
        <!--&lt;!&ndash; 忽略列,不生成bean 字段 &ndash;&gt;-->
        <!--&lt;!&ndash; <ignoreColumn column="FRED" /> &ndash;&gt;-->
        <!--&lt;!&ndash; 指定列的java数据类型 &ndash;&gt;-->
        <!--&lt;!&ndash; <columnOverride column="LONG_VARCHAR_FIELD" jdbcType="VARCHAR" /> &ndash;&gt;-->
        <!--</table>-->
        <table schema="" tableName="t_hibernate_book" domainObjectName="HBook"
               enableCountByExample="false" enableDeleteByExample="false"
               enableSelectByExample="false" enableUpdateByExample="false">
        </table>
        <table schema="" tableName="t_hibernate_category" domainObjectName="Category"
               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_order" domainObjectName="Order"
               enableCountByExample="false" enableDeleteByExample="false"
               enableSelectByExample="false" enableUpdateByExample="false">
        </table>
        <table schema="" tableName="t_hibernate_order_item" domainObjectName="OrderItem"
               enableCountByExample="false" enableDeleteByExample="false"
               enableSelectByExample="false" enableUpdateByExample="false">
        </table>
    </context>
</generatorConfiguration>

自动生成实体

创建一个 名为 OrderItemVo 的类,继承OrderItem类,及属性有Order对象

<!--  resultMap的映射-->
  <resultMap id="OrderVoMap" type="com.lya.vo.OrderVo" >
  <result column="order_id" property="orderId"></result>
  <result column="order_no" property="orderNo"></result>
    <!--    一个对应多个-->
    <collection property="orderItems" ofType="com.lya.model.OrderItem">
      <result column="order_id" property="orderId"></result>
      <result column="order_no" property="orderNo"></result>
      <result column="order_id" property="orderId"></result>
      <result column="order_no" property="orderNo"></result>
    </collection>
  </resultMap>
  <select id="byoid" resultMap=" " parameterType="java.lang.Integer" >
  select * from t_hibernate_order o ,
  t_hibernate_order_item ot where o.order_id = ot.oid
  and o.order_id = #{oid}
  </select>

在自动生成的 OrderItemMapper 接口中进行增加以下代码

OrderItemVo selectByBiid(@Param("oiid") Integer oiid);

 

创建一个接口名为 : OrderItemBiz 接口

package com.lya.biz;
import com.lya.vo.OrderItemVo;
/**
 * @author 程序猿-小李哥
 * @site www.xiaolige.com
 * @company 猪八戒有限集团
 * @create 2023-09-04-9:38
 */
public interface OrderItemBiz {
    OrderItemVo selectByBiid(Integer oiid);
}

创建一个实现了名为 OrderItemBizImpl

package com.lya.biz.impl;
import com.lya.biz.OrderItemBiz;
import com.lya.mapper.OrderItemMapper;
import com.lya.model.OrderItem;
import com.lya.vo.OrderItemVo;
import org.springframework.beans.factory.annotation.Autowired;
/**
 * @author 程序猿-小李哥
 * @site www.xiaolige.com
 * @company 猪八戒有限集团
 * @create 2023-09-04-9:40
 */
public class OrderItemBizImpl implements OrderItemBiz {
    @Autowired
    private OrderItemMapper orderItemMapper;
    @Override
    public OrderItemVo selectByBiid(Integer oiid) {
        return orderItemMapper.selectByBiid(oiid);
    }
}

测试:

 

二,一对多

创建一个 名为 OrdeVo 的类,继承Order

package com.lya.vo;
import com.lya.model.Order;
import com.lya.model.OrderItem;
import java.util.ArrayList;
import java.util.List;
/**
 * @author 程序猿-小李哥
 * @site www.xiaolige.com
 * @company 猪八戒有限集团
 * @create 2023-08-26-16:57
 */
public class OrderVo extends Order {
    private List<OrderItem>  orderItems = new ArrayList<>();
    public List<OrderItem> getOrderItems() {
        return orderItems;
    }
    public void setOrderItems(List<OrderItem> orderItems) {
        this.orderItems = orderItems;
    }
}

在自动生成的 OrderMapper.xml 配置文件中增加以下配置

<resultMap id="OrderVoMap" type="com.lya.vo.OrderVo">
      <result column="order_id" property="orderId" ></result>
      <result column="order_no" property="orderNo" ></result>
    <collection property="orderItems" ofType="com.lya.model.OrderItem">
      <result column="order_item_id" property="orderItemId" ></result>
      <result column="product_id" property="productId" ></result>
      <result column="quantity" property="quantity" ></result>
      <result column="oid" property="oid" ></result>
    </collection>
  </resultMap>
  <select id="selectByOid" resultMap="OrderVoMap" 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>

在自动生成的 OrderMapper接口中进行增加以下代码

OrderVo selectByOid(@Param("oid") Integer oid);

创建一个接口名为 : OrderBiz 接口

package com.lya.biz;
import com.lya.vo.OrderVo;
/**
 * @author 程序猿-小李哥
 * @site www.xiaolige.com
 * @company 猪八戒有限集团
 * @create 2023-09-04-10:04
 */
public interface OrderBiz {
    OrderVo selectByOid(Integer oid);
}

创建一个实现类,名为 OrderBizImpl

package com.lya.biz.impl;
import com.lya.biz.OrderBiz;
import com.lya.mapper.OrderMapper;
import com.lya.vo.OrderVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
 * @author 程序猿-小李哥
 * @site www.xiaolige.com
 * @company 猪八戒有限集团
 * @create 2023-09-04-10:05
 */
@Service
public class OrderBizImpl implements OrderBiz {
    @Autowired
    private OrderMapper orderMapper;
    @Override
    public OrderVo selectByOid(Integer oid) {
        return orderMapper.selectByOid(oid);
    }
}

测试:

@Autowired
    private OrderBiz orderBiz;
    @Test
    public void selectByOid() {
        OrderVo orderVo = orderBiz.selectByOid(7);
        System.out.println(orderVo);
        orderVo.getOrderItems().forEach(System.out::println);
    }

三,多对多

在自动生成的 HBookMapper.xml 配置文件中增加以下配置

<resultMap id="HBookVoMap" type="com.lya.vo.HBookVo" >
    <result column="book_id" property="bookId"></result>
    <result column="book_name" property="bookName"></result>
    <result column="price" property="price"></result>
    <collection property="categories" ofType="com.lya.model.Category">
      <result column="category_id" property="categoryId"></result>
      <result column="category_name" property="categoryName"></result>
    </collection>
  </resultMap>
  <select id="selectByBookId" resultMap="HBookVoMap" 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>

在自动生成的 HBookMapper 接口 中增加以下方法

HBookVo selectByBookId(@Param("bid") Integer bid);

创建一个接口名为 HBookBiz

package com.lya.biz;
import com.lya.vo.HBookVo;
import org.apache.ibatis.annotations.Param;
/**
 * @author 程序猿-小李哥
 * @site www.xiaolige.com
 * @company 猪八戒有限集团
 * @create 2023-09-04-10:13
 */
public interface HBookBiz {
    HBookVo selectByBookId(@Param("bid") Integer bid);
}

创建一个实现类,名为 HBookBizImpl

package com.lya.biz.impl;
import com.lya.biz.HBookBiz;
import com.lya.mapper.HBookMapper;
import com.lya.vo.HBookVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
 * @author 程序猿-小李哥
 * @site www.xiaolige.com
 * @company 猪八戒有限集团
 * @create 2023-09-04-10:13
 */
@Service
public class HBookBizImpl implements HBookBiz {
    @Autowired
    private HBookMapper hBookMapper;
    @Override
    public HBookVo selectByBookId(Integer bid) {
        return hBookMapper.selectByBookId(bid);
    }
}

测试

@Autowired
    private HBookBiz hbookBiz;
    @Test
    public void selectByBookId() {
        HBookVo hBookVo = hbookBiz.selectByBookId(8);
        System.out.println(hBookVo);
        hBookVo.getCategories().forEach(System.out::println);
    }

总结

学习Mybatis的关联关系映射可以带来以下收获和认识:

1. 数据库关系的抽象:学习MyBatis的关联关系映射可以有助于我们理解数据库中表与表之间的关系,如一对一和一对多关系。这可以提升我们对数据模型的理解和设计能力。

2. 对象关系映射(ORM)的学习:MyBatis采用了ORM的思想,通过映射配置将数据库表与Java对象进行关联。学习MyBatis的关联关系映射可以帮助我们掌握ORM的基本原理和实践技巧。

3. 数据库操作的灵活性:MyBatis的关联关系映射使得数据库操作更加灵活,能够方便地进行多表查询或关联查询。这有助于我们优化数据库访问性能,并提供更好的数据查询和操作能力。

4. 代码重用和维护性:通过MyBatis的关联关系映射,我们可以将一对一或一对多关系的查询逻辑封装成可复用的SQL语句或映射文件片段,提高代码的重用性和可维护性。

5. 高效的数据库访问:MyBatis的关联关系映射能够有效地利用数据库的连接和查询优化,减少不必要的数据库访问,提高数据库操作的效率。

这些收获和认识将帮助我们更好地应对实际项目中的数据库操作需求,并提升我们作为Java程序员的能力和竞争力。

 

相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
3月前
|
SQL XML Java
8、Mybatis-Plus 分页插件、自定义分页
这篇文章介绍了Mybatis-Plus的分页功能,包括如何配置分页插件、使用Mybatis-Plus提供的Page对象进行分页查询,以及如何在XML中自定义分页SQL。文章通过具体的代码示例和测试结果,展示了分页插件的使用和自定义分页的方法。
8、Mybatis-Plus 分页插件、自定义分页
|
3月前
|
SQL Java 测试技术
3、Mybatis-Plus 自定义sql语句
这篇文章介绍了如何在Mybatis-Plus框架中使用自定义SQL语句进行数据库操作。内容包括文档结构、编写mapper文件、mapper.xml文件的解释说明、在mapper接口中定义方法、在mapper.xml文件中实现接口方法的SQL语句,以及如何在单元测试中测试自定义的SQL语句,并展示了测试结果。
3、Mybatis-Plus 自定义sql语句
|
3月前
|
SQL Java Kotlin
MybatisPlus怎么拓展自定义BaseMapper
通过扩展Mybatis-Plus的`BaseMapper`,可以自定义SQL模板以满足特定业务需求。例如,当遇到唯一键冲突而不希望抛出异常时,可使用`INSERT IGNORE`语法。首先,创建`InsertIgnore`类继承`AbstractMethod`并定义`insertIgnore`方法及其SQL模板。接着,在自定义的`UltraBaseMapper`接口中声明`insertIgnore`方法,并让业务Mapper继承此接口。最后,通过`UltraSqlInjector`类将`InsertIgnore`方法注册到Mybatis-Plus插件中。
152 1
|
17天前
|
SQL 缓存 Java
【详细实用のMyBatis教程】获取参数值和结果的各种情况、自定义映射、动态SQL、多级缓存、逆向工程、分页插件
本文详细介绍了MyBatis的各种常见用法MyBatis多级缓存、逆向工程、分页插件 包括获取参数值和结果的各种情况、自定义映射resultMap、动态SQL
【详细实用のMyBatis教程】获取参数值和结果的各种情况、自定义映射、动态SQL、多级缓存、逆向工程、分页插件
|
2月前
|
SQL XML Java
mybatis复习04高级查询 一对多,多对一的映射处理,collection和association标签的使用
文章介绍了MyBatis中高级查询的一对多和多对一映射处理,包括创建数据库表、抽象对应的实体类、使用resultMap中的association和collection标签进行映射处理,以及如何实现级联查询和分步查询。此外,还补充了延迟加载的设置和用法。
mybatis复习04高级查询 一对多,多对一的映射处理,collection和association标签的使用
|
2月前
|
SQL XML Java
mybatis复习02,简单的增删改查,@Param注解多个参数,resultType与resultMap的区别,#{}预编译参数
文章介绍了MyBatis的简单增删改查操作,包括创建数据表、实体类、配置文件、Mapper接口及其XML文件,并解释了`#{}`预编译参数和`@Param`注解的使用。同时,还涵盖了resultType与resultMap的区别,并提供了完整的代码实例和测试用例。
mybatis复习02,简单的增删改查,@Param注解多个参数,resultType与resultMap的区别,#{}预编译参数
|
4月前
|
SQL Java 数据库连接
idea中配置mybatis 映射文件模版及 mybatis plus 自定义sql
idea中配置mybatis 映射文件模版及 mybatis plus 自定义sql
92 3
|
1月前
|
Java 数据库连接 Maven
mybatis使用一:springboot整合mybatis、mybatis generator,使用逆向工程生成java代码。
这篇文章介绍了如何在Spring Boot项目中整合MyBatis和MyBatis Generator,使用逆向工程来自动生成Java代码,包括实体类、Mapper文件和Example文件,以提高开发效率。
112 2
mybatis使用一:springboot整合mybatis、mybatis generator,使用逆向工程生成java代码。
|
1月前
|
SQL JSON Java
mybatis使用三:springboot整合mybatis,使用PageHelper 进行分页操作,并整合swagger2。使用正规的开发模式:定义统一的数据返回格式和请求模块
这篇文章介绍了如何在Spring Boot项目中整合MyBatis和PageHelper进行分页操作,并且集成Swagger2来生成API文档,同时定义了统一的数据返回格式和请求模块。
54 1
mybatis使用三:springboot整合mybatis,使用PageHelper 进行分页操作,并整合swagger2。使用正规的开发模式:定义统一的数据返回格式和请求模块
|
1月前
|
前端开发 Java Apache
Springboot整合shiro,带你学会shiro,入门级别教程,由浅入深,完整代码案例,各位项目想加这个模块的人也可以看这个,又或者不会mybatis-plus的也可以看这个
本文详细讲解了如何整合Apache Shiro与Spring Boot项目,包括数据库准备、项目配置、实体类、Mapper、Service、Controller的创建和配置,以及Shiro的配置和使用。
318 1
Springboot整合shiro,带你学会shiro,入门级别教程,由浅入深,完整代码案例,各位项目想加这个模块的人也可以看这个,又或者不会mybatis-plus的也可以看这个