十三、多表关联查询
1. 业务装配实现
业务装配实现多表查询(多对一)
mapper 层只做单表查询操作, 在 service 层进行手动装配,实现关联查询的结果.
(1) 实体类
创建班级类(Clazz) 和学生类(Student), 并在 Student 中添加一个 Clazz 类型的属性, 用于表示学生的班级信息.
 
(2) mapper 层
提供
<mapper namespace="com.bjsxt.mapper.StudentMapper">
<select id="selAll" resultType="student">
select * from t_student
</select>
</mapper>
<mapper namespace="com.bjsxt.mapper.ClazzMapper">
<select id="selById" resultType="clazz" parameterType="int">
select * from t_class where id=#{0}
</select>
</mapper>
 
(3) service 层
调用
public class StudentServiceImpl implements StudentService {
@Override
public List<Student> selAll() {
SqlSession session = MyBatisUtil. getSession();
// 学生mapper
StudentMapper stuMapper = session.getMapper(StudentMapper. class);
// 班级mapper
ClazzMapper clsMapper = session.getMapper(ClazzMapper. class);
// 查询所有学生信息
List<Student> list = stuMapper.selAll();
// 为每一个student组装班级信息
for (Student student : list) {
student.setClazz(clsMapper.selById(student.getCid()));
}
session.close();
return list;
}
}
 
(4) 测试代码
public static void main(String[] args) {
StudentService ss = new StudentServiceImpl();
List<Student> list = ss.selAll();
for (Student student : list) {
System. out.println(student);
}
}

2. 单个对象(N+1)
resultMap 的N+1方式实现多表查询(多对一)
(1) 实体类
创建班级类(Clazz) 和学生类(Student), 并在 Student 中添加一个 Clazz 类型的属性, 用于表示学生的班级信息.
 
(2) mapper 层
提供
<association>用于关联一个对象
property: 指定要关联的属性名
select: 设定要继续引用的查询, namespace+id
column: 查询时需要传递的列
<mapper namespace="com.bjsxt.mapper.StudentMapper">
<resultMap type="student" id="smap">
<!-- N+1查询时, 同名映射可以省略, 但是只能使用一次 -->
<result property="cid" column="cid" />
<!-- 用于关联一个对象 -->
<association property="clazz"
select="com.bjsxt.mapper.ClazzMapper.selById"
column="cid"></association>
</resultMap>
<select id="selAll" resultMap="smap">
select * from t_student
</select>
</mapper>

<mapper namespace="com.bjsxt.mapper.ClazzMapper">
<select id="selById" resultType="clazz" parameterType="int">
select * from t_class where id=#{0}
</select>
</mapper>
 
(3) service 层
由于装配已经完成, service 层只需要调用 mapper 即可, 不需要再进行装配了 .
public class StudentServiceImpl implements StudentService {
@Override
public List<Student> selAll() {
SqlSession session = MyBatisUtil. getSession();
// 学生mapper
StudentMapper stuMapper = session.getMapper(StudentMapper. class);
List<Student> list = stuMapper.selAll();
session.close();
return list;
}
}
 
3. 单个对象(关联)
resultMap 的关联方式实现多表查询 (多对一)
(1) mapper 层
1) 在 StudentMapper. xml 中定义多表连接查询 SQL 语句, 一次性查到需要的所有数据, 包括对应班级的信息.
2) 通过<resultMap>定义映射关系, 并通过<association>指定对象属性的映射关系. 可以把<association>看成一个<resultMap>使用 . javaType 属性表示当前对象, 可以写全限定路径或别名 .
<resultMap type="student" id="smap">
<id property="id" column="sid" />
<result property="name" column="sname" />
<result property="age" column="age" />
<result property="gender" column="gender" />
<result property="cid" column="cid" />
<association property="clazz" javaType="clazz">
<id property="id" column="cid" />
<result property="name" column="cname" />
<result property="room" column="room" />
</association>
</resultMap>
<select id="selAll" resultMap="smap">
select s.id sid, s.name sname, s.age, s.gender, c.id cid, c.name cname, c.room
from t_student s
left join t_class c
on s.cid=c.id
</select>
 
4. 集合对象(N+1)
resultMap 的 N+1 方式实现多表查询(一对多)
(1) 实体类
在班级类中定义一个学生集合, 用于存放该班级的所有学生信息.
 
(2) mapper 层
提供
在
<collection>用于关联一个集合
property: 指定要关联的属性名
select: 设定要继续引用的查询, namespace+id
column: 查询时需要传递的列
<mapper namespace="com.bjsxt.mapper.ClazzMapper">
<resultMap type="clazz" id="cmap">
<id property="id" column="id" />
<collection property="stus"
select="com.bjsxt.mapper.StudentMapper.selByCid"
column="id"></collection>
</resultMap>
<select id="selAll" resultMap="cmap">
select * from t_class
</select>
</mapper>
<mapper namespace="com.bjsxt.mapper.StudentMapper">
<select id="selByCid" resultType="student" parameterType="int">
select * from t_student where cid=#{0}
</select>
</mapper>
 
(3) service 层
public class ClazzServiceImpl implements ClazzService {
@Override
public List<Clazz> selAll() {
SqlSession session = MyBatisUtil. getSession();
ClazzMapper mapper = session.getMapper(ClazzMapper. class);
List<Clazz> list = mapper.selAll();
session.close();
return list;
}
}

5. 集合对象(关联)
resultMap 的关联方式实现多表查询(一对多)
(1) 在 ClazzMapper. xml 中定义多表连接查询 SQL 语句, 一次性查到需要的所有数据, 包括对应学生的信息.
(2) 通过<resultMap>定义映射关系, 并通过<collection>指定集合属性泛型的映射关系. 可以把<collection>看成一个<resultMap>使用 . ofType 属性表示集合的泛型, 可以写全限定路径或别名 .
<mapper namespace="com.bjsxt.mapper.ClazzMapper">
<resultMap type="clazz" id="cmap">
<id property="id" column="cid" />
<result property="name" column="cname" />
<result property="room" column="room" />
<collection property="stus" javaType="list" ofType="student">
<id property="id" column="sid" />
<result property="name" column="sname" />
<result property="age" column="age" />
<result property="gender" column="gender" />
<result property="cid" column="cid" />
</collection>
</resultMap>
<select id="selAll" resultMap="cmap">
select c.id cid, c.name cname, c.room, s.id sid, s.name sname, s.age, s.gender
from t_student s
right join t_class c
on s.cid=c.id
</select>
</mapper>
 
6. Auto-Mapping多表查询
通过
(1) 通过 MyBatis 的 Auto-Mapping 机制及数据库查询时的别名结合, 可以方便的实现多表查询.
(2) SQL 语句中, 别名出现特殊符号时, 必须进行处理. MySQL可以使用(``) 符号, Oracle 可以使用("") 符号.
<mapper namespace="com.bjsxt.mapper.StudentMapper">
<select id="selAll" resultType="student">
select s.id, s.name, s.age, s.gender, s.cid, c.id `clazz.id`, c.name `clazz.name`, c.room `clazz.room`
from t_student s
left join t_class c
on s.cid=c.id
</select>
</mapper>