文章目录
1. 多表联合查询基础
1.1 多表关系
- 一对一:左表中一条数据唯一对应右表的一条数据,如班级表对应班级详情表
- 多对一:左表中多条数据对应右表的一条数据,如学生表对应班级表
- 一对多:左表中一条数据对应右表的多条数据,如班级表对应学生表
- 多对多:左表中多条数据对应右表的多条数据,反之亦然,如学生表对应教师表
1.2 多表联合查询的sql语句
- 内连接([inner] join … on …): 返回左表和右表都存在的数据
- 左外连接(left [outer] join… on…): 返回左表中的全部数据,如果右表没有数据显示null
- 右外连接(right [outer] join… on…): 返回右表中的全部数据,如果左表没有数据显示null
- 满外连接(full [outer] join… on…): 返回左右表中的全部数据
1.3 Mybatis关联查询的实现方式
-
使用单表查询,在业务层手动装配
-
采用多表联合查询,使用resultTpye自动装配
-
使用resultMap自动装配,又分为多表联合查询和单表N+1次查询
2. 一对一(多对一),单表查询业务层装配
需求:查询所有学生和学生所在班级的信息
- 实体类
public class Cls {
private int id;
private String name;
}
public class Stu {
private int id;
private String name;
private int cid;
private Cls cls;
}
- Mapper
public interface StuMapper {
//查询全部学生
List<Stu> queryAll() throws Exception;
}
public interface ClsMapper {
//根据id查询数据
Cls queryById(int id) throws Exception;
}
- mapper映射文件
<select id="queryAll" resultType="com.bodhixu.mybatis.bean.Stu">
select * from stu
</select>
<select id="queryById" resultType="com.bodhixu.mybatis.bean.Cls" parameterType="int">
select * from cls where id = #{id}
</select>
- 业务层装配
//① 查询所有学生的信息
List<Stu> stus = stuMapper.queryAll();
//② 遍历学生,根据学生的班级id,查询指定班级的信息
for (Stu stu : stus) {
Cls cls = clsMapper.queryById(stu.getCid());
stu.setCls(cls);
}
3. 一对一(多对一),resultType自动装配
需求:查询所有学生和学生所在班级的信息
可以使用resultType属性,需要创建查询结果对应的实体类StuClsVo,然后查询语句中通过列别名对应结果实体类的属性。
public class StuClsVo {
private long sid; //学生编号
private String sname; //学生姓名
private long cid; //班级编号
private String cname; //班级名称
}
public interface StuClsMapper {
//查询全部学生班级信息
List<StuClsVo> queryAll();
}
<!-- 一对一查询,通过列别名对应实体的属性 -->
<select id="queryAll" resultType="com.bodhixu.ssm.bean.StuClsVo">
select s.id sid, s.name sname, s.cid, c.name cname
from stu s
left join clse c
on s.cid = c.id
</select>
4. 一对一(多对一),resultMap使用联合查询
resultMap的意思就是结果集映射,可以将一个复杂查询的结果映射到一个实体类上。
public class Stu {
private long sid;
private String name;
private Cls cls;
}
<!-- 使用resultMap,通过多表联合查询自动装配-->
<!--
resultMap: 指定查询结果的映射规则
- type: 查询结果所对应的实体类类型
- id: 给当前映射规则的编号
-->
<resultMap type="com.bodhixu.mybatis.bean.Stu" id="stuClsResultMap">
<!-- id: 映射主键
- column: 查询结果的列名
- property: 对应的属性的列名
-->
<id column="sid" property="id"/>
<!-- result:映射普通列 -->
<result column="name" property="name"/>
<!-- association关联:映射关联的bean对象
- property: 对应的属性名称
- javaType: bean对应的数据类型
-->
<association property="cls" javaType="com.bodhixu.mybatis.bean.Cls">
<id column="cid" property="id"/>
<result column="cname" property="name"/>
</association>
</resultMap>
<!-- resultMap:值是自定义映射规则的id -->
<select id="queryAll" resultMap="stuClsResultMap">
SELECT s.id sid, s.name, s.cid, c.name cname
FROM stu s
JOIN cls c
ON s.cid = c.id
</select>
5. 一对一(多对一),resultMap使用N+1次单表查询
先查询学生信息,将学生的班级编号作为班级查询的参数
public class Stu {
private long sid;
private String name;
private Cls cls;
}
<!-- 使用ResultMap的N+1次(单表查询) -->
<resultMap type="com.bodhixu.mybatis.bean.Stu" id="stuClsMap">
<id column="id" property="id"/>
<result column="name" property="name"/>
<!-- select:调用那个mapper接口中的那个方法实现二次查询
column:指明二次查询采用哪列作为查询参数条件
-->
<association property="cls" select="com.bodhixu.mybatis.mapper.ClsMapper.queryById" column="cid"></association>
</resultMap>
<select id="queryAll" resultMap="stuClsMap">
select * from stu <!--得到 id,name,cid -->
</select>
6. 一对多,单表查询业务层装配
需求:查询所有班级和班级所属学生的信息
- 实体类
public class Stu {
private int id;
private String name;
private int cid;
}
public class Cls {
private int id;
private String name;
private List<Stu> stus;
}
- Mapper
public interface StuMapper {
//根据班级编号查询指定班级的学生
List<Stu> queryByCid(int cid) throws Exception;
}
public interface ClsMapper {
//查询全部数据
List<Cls> queryAll() throws Exception;
}
- mapper映射文件
<select id="queryByCid" resultType="com.bodhixu.mybatis.bean.Stu" parameterType="int">
select * from stu where cid = #{cid}
</select>
<select id="queryAll" resultType="com.bodhixu.mybatis.bean.Cls">
select * from cls
</select>
- 业务层装配
//① 查询班级表,获得所有班级的集合
List<Cls> clses = clsMapper.queryAll();
//② 遍历班级集合,根据班级id,查询学生表获得当前班级下学生的集合
for (Cls cls : clses) {
//根据班级id,查询学生表获得当前班级下学生的集合
List<Stu> stus = stuMapper.queryByCid(cls.getId());
cls.setStus(stus);
}
7. 一对多,resultMap使用联合查询
public class Cls {
private long cid;
private String name;
private List<Stu> stus;
}
<resultMap type="com.bodhixu.mybatis.bean.Cls" id="clsStuMap">
<id column="id" property="id"/>
<result column="name" property="name"/>
<!-- collection: 集合属性的映射
- ofType: 集合中元素属性的类型
-->
<collection property="stus" ofType="com.bodhixu.mybatis.bean.Stu">
<id column="sid" property="id"/>
<result column="sname" property="name"/>
<result column="id" property="cid"/>
</collection>
</resultMap>
<select id="queryAllClsStu" resultMap="clsStuMap">
SELECT c.id, c.name, s.id sid, s.name sname
FROM cls c
LEFT JOIN stu s
ON c.id = s.cid
</select>
8. 一对多,resultMap使用N+1次查询
先查询班级信息,再将班级编号作为查询班级中学生信息的参数。
<!-- 使用ResultMap:采用单表n+1次查询 -->
<resultMap type="com.bodhixu.mybatis.bean.Cls" id="clsStuMap">
<id column="id" property="id"/>
<result column="name" property="name"/>
<collection property="stus" ofType="com.bodhixu.mybatis.bean.Stu"
select="com.bodhixu.mybatis.mapper.StuMapper.queryByCid" column="id">
</collection>
</resultMap>
<select id="queryAllClsStu" resultMap="clsStuMap">
select * from cls
</select>