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. 连表查询遵循:左连接保证数据完整,外键关联保证关系正确
相关推荐
可乐鸡翅yeah_5 分钟前
HLS流媒体首屏起播慢深度优化,从分片、索引、播放器全链路调优
开发语言·javascript·ecmascript·m3u8·m3u8在线
白远山7 分钟前
货运跑腿搬家平台开发实战:从需求分析到落地部署指南
数据库·数据挖掘·需求分析
luj_17687 分钟前
生物体如何应对功能击穿?
c语言·开发语言·c++·经验分享·算法
luj_176810 分钟前
击穿分析五大关键步骤
开发语言·网络·c++·经验分享·算法
wuyk55511 分钟前
从零吃透 MQTT 通信|第 11 章 MQTT 项目调试验证、性能优化、常见疑难问题、OTA 升级基础
c语言·开发语言·stm32·学习·性能优化
步行cgn15 分钟前
Spring 注入 Properties 详解
java·python·spring
海盗123415 分钟前
微软技术日报 2026-09-14:Rust 升为微软一级语言,云业务重组为智能体与基础设施
开发语言·microsoft·rust
星空16 分钟前
Map<String, String>`Map`是接口,不能直接 new
java·前端·算法
liangbo716 分钟前
12-JVM 调优方法论与参数速查
java·jvm
干到60岁退休的码农18 分钟前
16.过滤器中处理异常响应返回
java·spring boot·mybatis