MyBatis 学习(五)之 高级映射

目录

1 association 和 collection 介绍

2 案例分析

3 一对一关联和一对多关联

4 参考文档


1 association 和 collection 介绍

        在之前的 SQL 映射文件中提及了 resultMap 元素的 association collection 标签,这两个标签是用来关联查询的,它们的属性几乎一致,以下是对它们属性的描述,红色标注的是常用属性。

属性描述
property实体类属性名
column数据库字段名或者其别名
javaType实体类属性的 Java 类型
jdbcType数据库列的数据类型
ofType指定关联对象的类型。它通常用于泛型类型的情况,以确保正确的类型转换
select指定一个子查询,用于加载关联的对象
fetchType用于控制加载策略,比如立即加载还是延迟加载。常见的取值有 lazy(延迟加载)和 eager(立即加载)
resultMap引用预定义的结果映射,以便更灵活地配置关联对象的映射规则
resultSet指定结果集的名称,以便在多结果集的情况下进行区分
autoMapping是否自动映射所有列到目标对象的属性上。默认为 true,表示自动映射;设置为 false 则表示不自动映射
columnPrefix当使用内连接查询时,这个属性可以用来指定前缀,以区分关联表的列名
foreignColumn指定外键对应的列名
notNullColumn指定一个列名,只有当该列的值不为 null 时,才会执行关联查询
typeHandler自定义的类型处理器

2 案例分析

以典型的 员工 (Employee) 和部门 (Department) 为例

  • 一个员工只能在一个部门:Employee -> Department(一对一)
  • 一个部门可以包含多个员工:Department -> Employee(一对多)

以用户 (User) 和角色 (Role) 为例,两者成了一个双向的一对多,从而变成了多对多,不做介绍

  • 一个用户可以拥有多个角色:User -> Role(一对多)
  • 一个角色可以赋予多个用户:Role -> User(一对多)

表 department 和 表 employee

# 创建 department 表
drop table if exists department;
create table department(
department_id int(11) primary key auto_increment, #主键,自增
department_name varchar(255)
)charset=utf8;

# 插入数据
insert into department(department_name) values
('开发部'),
('人力资源部'),
('市场营销部'),
('财务部'),
('行政部'),
('监察部'),
('客服服务部');

# 创建 employee 表
drop table if exists employee;
create table employee(
employee_id int(11) primary key auto_increment, #主键,自增
employee_name varchar(255),
employee_age int(11),
employee_sex char(32),
employee_email varchar(255),
employee_address varchar(255),
department_id int(11)
)charset=utf8;

# 插入数据
insert into employee values
(1, '唐浩荣', 23, 1, '15477259875@163.com', '中国上海浦东区', 1),
(2, '黄飞鸿', 32, 1, '86547547@qq.com', '大清广东', 2),
(3, '十三姨', 18, 0, '520520520@gmail.com', '大清广东', 3),
(4, '纳兰元述', 28, 1, '545627858@qq.com', '大清京师', 5),
(5, '梁宽', 31, 1, '8795124578@qq.com', '大清广东', 7),
(6, '蔡徐坤', 20, 0, '4257895124@gmail.com', '四川成都', 4),
(7, '杨超越', 21, 0, '8746821252@qq.com', '中国北京', 7),
(8, '马保国', 66, 1, '6666666666@qq.com', '广东深圳', 6),
(9, '马牛逼', 45, 1, 'asdfg45678@163.com', '湖北武汉', 3);

3 一对一关联和一对多关联

工程目录

Department 类

public class Department {
    //部门id
    private Integer deptId;
    //部门名称
    private String deptName;

    //部门有哪些员工
    private List<Employee> employees;

    // Getter、Setter、toString 方法省略
}

Employee 类

public class Employee {
    //员工id
    private Integer empId;
    //员工名称
    private String empName;
    //员工年龄
    private Integer empAge;
    //员工性别
    private Integer empSex;
    //员工邮箱
    private String empEmail;
    //员工地址
    private String empAddress;

    //员工所属部门,和部门表构成一对一的关系,一个员工只能在一个部门
    private Department department;

    // Getter、Setter、toString 方法省略
}

创建 DepartmentMapper

public interface DepartmentMapper {
    //查询所有数据
    @Select("select * from department")
    @Results(id = "deptMap1", value = {
            @Result(property = "deptId", column = "department_id"),
            @Result(property = "deptName", column = "department_name"),
            // 一对多关联对象
            // 根据 department_id 来比较
            @Result(property = "employees", column = "department_id",
                many = @Many(select = "com.mapper.EmployeeMapper.selectEmpByDeptId"))
    })
    List<Department> selectAll();
    // 根据 id 查找部门
    @Select("select * from department where department_id = #{id}")
    @Results(id = "deptMap2", value = {
            @Result(property = "deptId", column = "department_id"),
            @Result(property = "deptName", column = "department_name")
    })
    Department findDepartmentById(int id);
}

创建 EmployeeMapper

public interface EmployeeMapper {
    //查询所有数据
    @Select("select * from employee")
    @Results(id = "empMap1", value = {
            @Result(property = "empId", column = "employee_id", id = true),
            @Result(property = "empName", column = "employee_name"),
            @Result(property = "empAge", column = "employee_age"),
            @Result(property = "empSex", column = "employee_sex"),
            @Result(property = "empEmail", column = "employee_email"),
            @Result(property = "empAddress", column = "employee_address"),
            // 一对一关联对象
            // 根据 department_id 来比较
            @Result(property = "department", column = "department_id",
                    one = @One(select = "com.mapper.DepartmentMapper.findDepartmentById"))}

    )
    List<Employee> selectAll();
    //根据员工id查询数据
    @Select("select * from employee where employee_id = #{id}")
    @ResultMap("empMap1")
    Employee selectEmpByEmpId(@Param("id") int empId);

    // 根据 department_id 查询数据
    @Select("select * from employee where department_id = #{id}")
    @ResultMap("empMap1")
    Employee selectEmpByDeptId(@Param("id") int deptId);
}

log4j.properties

log4j.rootLogger=DEBUG, Console
#Console
log4j.appender.Console=org.apache.log4j.ConsoleAppender
log4j.appender.Console.layout=org.apache.log4j.PatternLayout
log4j.appender.Console.layout.ConversionPattern=%d [%t] %-5p [%c] - %m%n
log4j.logger.java.sql.ResultSet=INFO
log4j.logger.org.apache=INFO
log4j.logger.java.sql.Connection=DEBUG
log4j.logger.java.sql.Statement=DEBUG
log4j.logger.java.sql.PreparedStatement=DEBUG

mysql.properties

url=jdbc:mysql://localhost:3306/study?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
name=root
password=123456
driver=com.mysql.cj.jdbc.Driver

MyBatis 配置文件 mybatis-config.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <!-- 通过properties标签,读取java配置文件的内容 -->
    <properties resource="mysql.properties" />
    <!-- 配置环境.-->
    <environments default="development">
        <environment id="development">
            <!--配置事务的类型-->
            <transactionManager type="JDBC"></transactionManager>
            <!--dataSource 元素使用标准的 JDBC 数据源接口来配置 JDBC 连接对象源 -->
            <dataSource type="POOLED">
                <!--配置连接数据库的4个基本信息-->
                <property name="url" value="${url}" />
                <property name="username" value="${name}" />
                <property name="password" value="${password}" />
                <property name="driver" value="${driver}" />
            </dataSource>
        </environment>
    </environments>
    <!--通过包 package 引入 SQL 映射文件-->
    <mappers>
        <package name="com.mapper"/>
    </mappers>
</configuration>

创建 EmployeeTest 测试类

public class EmployeeTest {
    //定义 SqlSession
    SqlSession sqlSession = null;
    //定义 EmployeeMapper 对象
    private EmployeeMapper mapper = null;

    @Before
    public void getSqlSession() throws IOException {
        //加载 mybatis 全局配置文件 Resources
        // 原 InputStream is = MybatisTest.class.getClassLoader().getResourceAsStream("mybatis-config.xml");
        InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
        //创建 SqlSessionFactory 对象
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
        //根据 sqlSessionFactory 产生 session
        sqlSession = sqlSessionFactory.openSession();
        // 创建Mapper接口的的代理对象,getMapper方法底层会通过动态代理生成 EmployeeMapper 的代理实现类
        mapper = sqlSession.getMapper(EmployeeMapper.class);
    }

    //查询所有员工数据
    @Test
    public void testSelectAll() {
        List<Employee> listEmployee = mapper.selectAll();
        for (Employee employee : listEmployee) {
            System.out.println(employee);
        }
        sqlSession.close();
    }

    //根据员工 id 查询数据
    @Test
    public void testSelectById() {
        Employee employee = mapper.selectEmpByEmpId(1);
        System.out.println(employee);
        sqlSession.close();
    }
}

测试结果

查询所有员工数据,包括员工所在部门(一个员工属于一个部门)

创建 DepartmentTest 测试类

public class DepartmentTest {
    //定义 SqlSession
    SqlSession sqlSession = null;
    //定义 DepartmentMapper 对象
    private DepartmentMapper mapper = null;

    @Before
    public void getSqlSession() throws IOException {
        //加载 mybatis 全局配置文件 Resources
        // 原 InputStream is = MybatisTest.class.getClassLoader().getResourceAsStream("mybatis-config.xml");
        InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
        //创建 SqlSessionFactory 对象
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
        //根据 sqlSessionFactory 产生 session
        sqlSession = sqlSessionFactory.openSession();
        // 创建Mapper接口的的代理对象,getMapper方法底层会通过动态代理生成 DepartmentMapper 的代理实现类
        mapper = sqlSession.getMapper(DepartmentMapper.class);
    }

    //查询所有部门数据
    @Test
    public void testSelectAll() {
        List<Department> listDepartment = mapper.selectAll();
        for (Department department : listDepartment) {
            System.out.println(department);
        }
        sqlSession.close();
    }

    //根据部门 id 查询 数据
    @Test
    public void testSelectById() {
        Department department = mapper.findDepartmentById(1);
        System.out.println(department);
        sqlSession.close();
    }
}

测试结果

查询所有部门信息,包括该部门有哪些员工(一个部门有多个员工)

4 参考文档

篇篇“参考”这位博主的文档。。。不过确实写的挺好的

Mybatis3详解(八)----高级映射之一对一映射 - 唐浩荣 - 博客园 (cnblogs.com)

Mybatis3详解(九)----高级映射之一对多映射 - 唐浩荣 - 博客园 (cnblogs.com)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/420815.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

中小企业“数智未来”行动|ZStack Cloud 荣获“推荐方案”奖

2月29日&#xff0c;以“数智未来 共创数字时代新篇章”为主题的中小企业“数智未来”行动在京成功举办&#xff0c;本次活动由中央广播电视总台央视频和中国中小企业协会作为联合观察单位&#xff0c;带来了一系列帮助中小企业成就业务新价值和数智化升级的优秀产品和方案&…

从入门到精通的Android进阶学习笔记整理,你有过迷茫吗

面试题 一般Android面试分为两部分&#xff1a;Java部分和Android部分&#xff0c;下面说一下自己面试过程遇到的一些具体题目和一些相关知识点。 一 JAVA相关 1&#xff09;JAVA基础 1.java基本数据类型有哪些&#xff0c;int&#xff0c; long占几个字节 2. 和 equals有什…

Mint_21.3 drawing-area和goocanvas的FB笔记(二)

一、goocanvas安装 Linux mint 21.3 库中带有 libgoocanvas-2.0-dev, 用sudo apt install libgoocanvas-2.0-dev 安装&#xff0c;安装完成后&#xff0c;检查一个 /usr/lib/x86_64-linux-gnu 下是否有libgoocanvas.so的软件链接。如果没有&#xff0c;或是 .so.x 等类似后面…

QT Widget: 自定义Widget组件及创建和使用动静态库

学习自定义Widget组件&#xff0c;书中的案例&#xff1a; // 自定义QmyBattery组件 // QmyBattery.c #include "qmybattery.h"QmyBattery::QmyBattery(QWidget *parent) : QWidget(parent) {}/** 1.QPainter的viewport()与window()分别代表着物理坐标与逻辑坐标区域…

类加载的基本流程

⭐ 作者&#xff1a;小胡_不糊涂 &#x1f331; 作者主页&#xff1a;小胡_不糊涂的个人主页 &#x1f4c0; 收录专栏&#xff1a;JavaEE &#x1f496; 持续更文&#xff0c;关注博主少走弯路&#xff0c;谢谢大家支持 &#x1f496; 类加载 1. 加载2. 验证3. 准备4. 解析5. 初…

maven项目报错Cannot resolve plugin org.apache.maven.plugins:maven-war-plugin:2.2

如果IDEA整合maven没有问题&#xff0c;还是报这个错误&#xff0c;很大可能是由于在下载过程中存在网络问题&#xff0c;导致文件下载一半而停止&#xff0c;但是已经在仓库中存在这个文件夹&#xff0c;解决方法是删除文件夹重新下载即可。 删除本地仓库下的\org\apache\mav…

Gophish+EwoMail 自建钓鱼服务器

GophishEwoMail 自建钓鱼服务器 文章目录 GophishEwoMail 自建钓鱼服务器1.前提准备2.搭建EwoMail邮件服务器1&#xff09;Centos7 防火墙操作2&#xff09;设置主机名3&#xff09;host配置4&#xff09;安装EwoMail5&#xff09;获取DKIM6&#xff09;端口服务介绍7&#xff…

JAVA的学习日记

JAVA的学习日记&#xff08;2024.3.1&#xff09;&#xff08;b站韩顺平老师课程学习笔记版&#xff09; ps:捡起忘光光的Java语言 Sublime //1. public是公有&#xff0c;class是类 //2. public class Hello表示Hello是一个类&#xff0c;是一个public公有的类 //3. Hello{…

1.1 创建第一个vue项目

cmd命令窗口运行 vue init webpack hellovue 注意&#xff0c;hellovue是项目名称&#xff0c;项目名称不能保存大写字母否者会报错 Sorry, name can no longer contain capital letters. 运行设个命令的时候可能会报错&#xff0c;根据提示先运行 npm i -g vue/cli-init …

在独立Unity工程中集成Vortex Studio

本文首发于&#xff1a;Unity3D入门教程09.01&#xff1a;在独立Unity工程中集成Vortex Studio 目的 在Unity中使用Vortex Studio引擎模拟Unity场景中的任何资源。 工程 打开桌面Unity Hub快捷方式 点击Open选择需要打开的工程&#xff0c;这里选择官方提供的默认工程C:\CM…

永磁同步电机无感FOC(龙伯格观测器)算法技术总结-实战篇

文章目录 1、ST龙伯格算法分析&#xff08;定点数&#xff09;1.1 符号说明1.2 最大感应电动势计算1.3 系数计算1.4 龙伯格观测器计算1.5 锁相环计算1.6 观测器增益计算1.7 锁相环PI计算&#xff08;ST&#xff09;1.8 平均速度的用意 2、启动策略2.1 V/F压频比控制2.2 I/F压频…

msvcp140.dll安装教程_最新msvcp140.dll丢失的解决方法

msvcp140.dll 是一个动态链接库 (DLL) 文件&#xff0c;它是 Microsoft Visual C 运行时库的一部分&#xff0c;特别对应的是 Visual Studio 2015 版本编译的 C 应用程序所需的关键组件。DLL 文件的设计目的是为了实现代码和数据的共享&#xff0c;这样多个应用程序就可以在同一…

C# 解决uploadify插件上传时造成session丢失问题

出现的问题&#xff1a; 在应用uploadify插件实现上传图片时&#xff0c;报了HTTP Error&#xff0c;经过在Network查看上传方法报错码是302&#xff0c;那这里就可以知道问题是什么了&#xff0c;HTTP 302是请求被重定向&#xff0c;如果你的uploadify处理上传方法有session验…

Vue3_2024_1天【Vue3创建和响应式,对比Vue2】

前言&#xff1a; Vue3对比Vue2版本&#xff0c;它在性能、功能、易用性和可维护性方面都有显著的提升和改进。 性能优化&#xff1a;模板编译器的优化、对Proxy的支持以及使用了更加高效的Virtual DOM算法等。这使得Vue3的打包大小减少了41%&#xff0c;初次渲染提速55%&#…

【K8S类型系统】一文梳理 K8S 各类型概念之间的关系(GVK/GVR/Object/Schema/RestMapper)

参考 k8s 官方文档 https://kubernetes.io/zh-cn/docs/reference/https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/ 重点 Kubernetes源码学习-kubernetes基础数据结构 - 知乎 重点 Kubernetes类型系统 | 李乾坤的博客 重点 k8s源码学习-三大核心数…

Harbor 的安装及使用

Harbor 安装官网手册&#xff1a; https://goharbor.io/docs/2.10.0/install-config/download-installer/ Harbor 发布包地址&#xff1a; https://github.com/goharbor/harbor/releases Harbor 的架构查看&#xff1a; https://github.com/goharbor/harbor/wiki/Architectur…

​MPV,汽车产品里一个特殊品类的进化过程

「汽车」可能是整个工业革命以来&#xff0c;所诞生出的最有趣的工业产品。 它不仅能产生工业的机械美&#xff0c;还诞生了一个独立的文化体系&#xff0c;在汽车的发展过程中&#xff0c;我们也能看到一些本来应功能而诞生的产品&#xff0c;最终走向了千家万户。 MPV 就是…

如何设置从小程序跳转到其它小程序

​有的商家有多个小程序&#xff0c;希望能够通过一个小程序链接到所有其它小程序&#xff0c;用户可以通过点击跳转链接实现从一个小程序跳转到另一个小程序。要怎么才能实现这样的跳转呢。下面具体介绍。 1. 设置跳转。在小程序管理员后台->分类管理&#xff0c;添加一个…

js截取图片地址后面的参数和在路径中截取文件名或后缀名

文章目录 前言截取地址 &#xff1f;后面的参数在路径中截取文件名或后缀名总结 前言 在处理网页上的图片资源或者其他类型的文件资源时&#xff0c;你可能会遇到需要使用这些技巧的情况。以下是一些具体的使用场景&#xff1a; 动态修改图片参数&#xff1a;如果你有一个图片U…

社交APP开发能给用户带来什么

现在的社交软件也非常的多&#xff0c;每款社交软件都有自己的特色&#xff0c;社交软件是日常中必备的软件&#xff0c;不管是生活交流还是感情工作交流都是比较方便的&#xff0c;因为社交软件满足了日常的远程交流问题&#xff0c;所以开发社交软件也会逐渐的流行起来的。 …