MyBatis 从入门到实战(二):代理 Dao 开发与多表关联查询

在 MyBatis 入门阶段,我们通常使用原生 Dao 方式编写数据访问层。但在实际企业开发中,更简洁、更规范的代理 Dao(Mapper 接口代理) 才是主流方案。它不需要我们手动实现 Dao 实现类,只需要定义接口与 XML 映射文件,由 MyBatis 自动生成代理对象完成数据库操作。

二、环境准备与实体类设计

本次案例以经典的 部门(Dept)- 员工(Emp) 模型为例:

1. 数据库表结构

  • 部门表 deptdid(主键)、dname
  • 员工表 empeid(主键)、enamesalarydno(外键,关联部门主键)

2. 实体类设计

Dept 实体类(一的一方)

java 复制代码
public class Dept {
    private Integer did;
    private String dname;

    // 一对多:一个部门包含多个员工
    private List<Emp> emp4;

    // 无参/有参构造、get/set、toString
}

Emp 实体类(多的一方)

java 复制代码
public class Emp {
    private Integer eid;
    private String ename;
    private Integer salary;
    private Integer dno;

    // 多对一:一个员工属于一个部门
    private Dept dept;

    // 无参/有参构造、get/set、toString
}

口诀:一对多加集合,多对一加对象。

三、代理 Dao 方式开发 CRUD

MyBatis 代理 Dao 开发遵循几个固定规则:

  1. Mapper 接口全类名与 XML 映射文件 namespace 一致
  2. 接口方法名与 XML 中 statement id 一致
  3. 方法入参与 parameterType 一致
  4. 方法返回值与 resultType/resultMap 一致

1. Mapper 接口定义

java 复制代码
public interface DeptMapper {
    List<Dept> selectAll();
}

public interface EmpMapper {
    Emp selectEmpById(Integer eid);
}

2. XML 映射文件

XML 复制代码
<!-- DeptMapper.xml -->
<mapper namespace="com.xxx.mapper.DeptMapper">
    <select id="selectAll" resultType="Dept">
        select * from dept
    </select>
</mapper>

3. 测试类

java 复制代码
@Test
public void testSelectAll() {
    SqlSession session = MyBatisUtil.getSession();
    DeptMapper mapper = session.getMapper(DeptMapper.class);
    List<Dept> deptList = mapper.selectAll();
    deptList.forEach(System.out::println);
    session.close();
}

到目前为止,基础 CRUD 可以完成。但当我们需要查询部门及其下属员工查询员工及其所属部门时,简单的 resultType 已经无法满足封装需求。

四、多表关联查询

1. 一对多查询:查询部门及其下属员工

需求:查询所有部门,并展示每个部门下的所有员工。

  • 一的一方:Dept
  • 多的一方:Emp
  • 封装方式:List<Emp>
  • XML 标签:<collection>
resultMap 配置
XML 复制代码
<resultMap id="DeptEmpMap" type="Dept">
    <id column="did" property="did"/>
    <result column="dname" property="dname"/>

    <!-- 一对多:集合映射 -->
    <collection property="emp4" ofType="Emp">
        <result column="ename" property="ename"/>
    </collection>
</resultMap>

<select id="selectAllDeptAndEmp" resultMap="DeptEmpMap">
    select d.did, d.dname, e.ename
    from dept d
    left join emp e on d.did = e.dno
</select>

2. 多对一查询:查询员工及其所属部门

需求:查询某个员工,以及他所属的部门信息。

  • 以 emp 为主表
  • 多对一使用 <association> 标签
  • 映射单个对象,使用 javaType
resultMap 配置
XML 复制代码
<resultMap id="EmpDeptMap" type="Emp">
    <id column="eid" property="eid"/>
    <result column="ename" property="ename"/>

    <!-- 多对一:单个对象映射 -->
    <association property="dept" javaType="Dept">
        <result column="dname" property="dname"/>
    </association>
</resultMap>

<select id="selectEmpWithDeptById" parameterType="int" resultMap="EmpDeptMap">
    select e.eid, e.ename, d.dname
    from emp e
    left join dept d on e.dno = d.did
    where e.eid = #{eid}
</select>

3. 连表 SQL 说明

sql 复制代码
SELECT e.eid, e.ename, d.did, d.dname
FROM emp e
LEFT JOIN dept d ON e.dno = d.did
WHERE e.eid = 1;
  • emp edept d 是表别名,用于区分字段、简化书写
  • 多表查询必须明确关联条件:主表主键 = 从表外键

五、总结

  1. 开发优先使用 Mapper 代理 Dao 方式,省略 Dao 实现类
  2. 单表查询用 resultType,多表关联 / 嵌套对象必须用 resultMap
  3. 一对多:<collection> + ofType + List
  4. 多对一:<association> + javaType + 单个对象
  5. 连表查询遵循:左连接保证数据完整,外键关联保证关系正确
相关推荐
复园电子3 小时前
企业级PDF批量盖章方案选型指南
数据库·pdf
Lhappy嘻嘻8 小时前
Java IO|File 文件操作 + 字节流 / 字符流完整笔记 + 递归删除文件实战
java·笔记·php
科技道人8 小时前
记录 默认置灰/禁用 app ‘Search Engine Selector‘ 的disable按钮
开发语言·前端·javascript
伊玛目的门徒8 小时前
试用leetcode之典中典 二数之和问题
java·算法·leetcode
AI-好学者9 小时前
阶段一-图数据库基础与PropertyGraph模型
数据库·rag·knowledge graph·graphrag
逝水无殇10 小时前
C# 异常处理详解
开发语言·后端·c#
其实防守也摸鱼11 小时前
运维--学习阶段问题解答(1)(自测)
linux·运维·服务器·数据库·学习·自动化·命令模式
懒鸟一枚11 小时前
深入理解 Linux 内存、Swap 交换分区与分页机制的关系
java·linux·数据库
龙仔72511 小时前
SQL Server 创建只读账号完整操作(分两种场景:SSMS图形界面 + T-SQL脚本)
数据库·sql·oracle
霁月的小屋11 小时前
生产环境中的事务实践——银行系统上线记(四)
数据库