在 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 开发遵循几个固定规则:
- Mapper 接口全类名与 XML 映射文件 namespace 一致
- 接口方法名与 XML 中 statement id 一致
- 方法入参与 parameterType 一致
- 方法返回值与 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是表别名,用于区分字段、简化书写- 多表查询必须明确关联条件:主表主键 = 从表外键
五、总结
- 开发优先使用 Mapper 代理 Dao 方式,省略 Dao 实现类
- 单表查询用
resultType,多表关联 / 嵌套对象必须用resultMap - 一对多:
<collection>+ofType+List - 多对一:
<association>+javaType+ 单个对象 - 连表查询遵循:左连接保证数据完整,外键关联保证关系正确