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. 连表查询遵循:左连接保证数据完整,外键关联保证关系正确
相关推荐
明月醉窗台2 小时前
Python-opencv批量处理文件夹中图像操作
开发语言·python·opencv
周末也要写八哥2 小时前
C++实际开发之泛型编程(模版编程)
java·开发语言·c++
好家伙VCC2 小时前
**发散创新:用 Rust实现游戏日引擎核心模块——从事件驱动到多线程调度的实战
java·开发语言·python·游戏·rust
m0_716430072 小时前
JavaScript中类属性与原型属性的覆盖规则详解
jvm·数据库·python
lzksword2 小时前
C++ Builder XE Idhttp下载网页数据
数据库
014-code2 小时前
Chronicle Queue:把 Disruptor 的数据落盘
java·服务器
m0_734949792 小时前
Redis如何降低快照对CPU的影响_合理分配RDB执行时机避开业务高峰期
jvm·数据库·python
Dxy12393102162 小时前
Python在图片上画圆形:从入门到实战
开发语言·python
小江的记录本2 小时前
【系统设计】《2026高频经典系统设计题》(秒杀系统、短链接系统、订单系统、支付系统、IM系统、RAG系统设计)(完整版)
java·后端·python·安全·设计模式·架构·系统架构