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

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

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

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

1. 数据库表结构

  • 部门表 dept:did(主键)、dname
  • 员工表 emp:eid(主键)、ename、salary、dno(外键,关联部门主键)

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 e、dept d 是表别名,用于区分字段、简化书写
  • 多表查询必须明确关联条件:主表主键 = 从表外键

五、总结

  1. 开发优先使用 Mapper 代理 Dao 方式,省略 Dao 实现类
  2. 单表查询用 resultType,多表关联 / 嵌套对象必须用 resultMap
  3. 一对多:<collection> + ofType + List
  4. 多对一:<association> + javaType + 单个对象
  5. 连表查询遵循:左连接保证数据完整,外键关联保证关系正确
相关推荐
Decay__2 小时前
05_MySQL 常用 SQL 大全 —— 诊断、管理、优化辅助 SQL 与三大系统库速查
运维·数据库·sql·mysql·架构
学长毕设5 小时前
基于SpringBoot的实验室资产管理系统
java·spring boot·后端
C^h5 小时前
c++ string
开发语言·c++
raindayinrain5 小时前
c++高性能--原子操作,无锁编程,操作顺序
开发语言·c++·性能优化
学逆向的5 小时前
C++ 合并命名空间
开发语言·c++·网络安全
Zhao-Jichao6 小时前
VS2026 打包 C++ 程序生成 EXE,借助 Installer Project 扩展工具
开发语言·c++
zzu123zsw6 小时前
从臃肿的模板调用到声明式契约:深入 UniHttp 动态代理与多渠道生命周期扩展
java·spring boot·microsoft·unihttp
学逆向的6 小时前
C 局部静态变量
c语言·开发语言·网络安全
小徐不徐说7 小时前
C++ 接口与插件设计:从工厂注册到 Qt 动态插件
数据库·c++·qt·系统架构·程序设计
大都督会赢的7 小时前
C++第一节课
开发语言·c++