目录
概述
准备工作
多对一
问题的引出
级联属性映射处理
association处理
分步查询
一对多
问题的引出
collection处理
分步查询
延迟加载解读
什么是延迟加载?
在mybatis中怎么开启延迟加载呢?
概述
MyBatis 的一对多、多对一,主要就是 resultMapresultMapresultMap 两个属性的使用,而一对多和多对一都是相互的,只是站的角度不同:
- 【一对多】association:一个复杂的类型关联。许多结果将包成这种类型
- 【多对一】collection:复杂类型的集合
准备工作
由于本文是作为解读处理,在这里将不再赘述工程的搭建,只在这里只带大家过一下我们准备的实体类和pojo对象
准备的表有俩张,一个是学生表(t_student),一个是班级表(t_clazz),学生表可以通过cid字段到班级表中查询到对应的班级,java程序控制的外键,俩张表的数据如下:
工程目录如下:
多对一
问题的引出
假设我们要去查询一个学生的信息,这个信息包括班级信息,我们在mysql如何进行查询呢?大家很自然而然的就会想到通过多表联查即可即以下语句:
SELECT * FROM t_student
LEFT JOIN t_clazz
ON t_clazz.`cid`=t_student.`cid`
WHERE sid=1
查询的结果如下:
记录返回给mybatis进行的数据的封装,就需要提供一个实体类student,那么这个的时候我们需要对这个实体类的属性进行考虑,多个学生对应一个班级也就是多对一,我们把班级作为一个实体类,学生的属性中有班级这一个属性。
班级类(clazz)如下:
@Data
public class Clazz {
private Long cid;
private String cname;
}
学生类(student)如下:
@Data
public class Student {
private Long sid;
private String sname;
private Clazz clazz;
}
Clazz clazz; 表示学生关联的班级对象。
级联属性映射处理
StudentMapper接口中编写接口
/**
* 根据id查询学生信息
* @param id
* @return
*/
Student selectById(@Param("id") Long id);
StudentMapper.xml中实现
<resultMap id="studentResultMap" type="com.study.pojo.Student">
<id property="sid" column="sid"/>
<result property="sname" column="sname"/>
<result property="clazz.cid" column="cid"/>
<result property="clazz.cname" column="cname"/>
</resultMap>
<select id="selectById" resultMap="studentResultMap">
SELECT * FROM t_student
LEFT JOIN t_clazz
ON t_clazz.`cid`=t_student.`cid`
WHERE sid=#{id}
</select>
级联属性映射,就是利用
resultMap
标签对属性和字段进行映射,内部对象的所属属性也进行映射,而SQL
语句就进行表的连接进行查询。例如:clazz.cid
测试代码:
@Test
public void test01(){
SqlSession session = SqlSessionUtil.openSession();
StudentMapper mapper = session.getMapper(StudentMapper.class);
Student student = mapper.selectById(1L);
System.out.println(student);
}
association处理
association
翻译为关联的意思。它是resultMap
标签中的一个子标签。也是用来处理映射的,当一对象属性中存在另一个对象时,可以利用association
指明其对象中属性及其对应映射。
其他位置都不需要修改,只需要修改resultMap中的配置:association即可。
分步查询
分步查询处理顾名思义将查询的步骤进行分步,在我们进行查询学生信息的时候,可以分为俩步
第一步先到学生表中查到学生的sid和sname,cid
第二步拿第一步中得到的cid去班级表中查询cname
具体实施
第一处:association中select位置填写sqlId。sqlId=namespace+id。其中column属性作为这条子sql语句的条件。
<resultMap id="studentResultMap" type="com.study.pojo.Student">
<id property="sid" column="sid"/>
<result property="sname" column="sname"/>
<association property="clazz"
select="com.study.mapper.ClazzMapper.selectById"
column="cid"></association>
</resultMap>
<select id="selectById" resultMap="studentResultMap">
SELECT * FROM t_student
LEFT JOIN t_clazz
ON t_clazz.`cid`=t_student.`cid`
WHERE sid=#{id}
</select>
第二处:在ClazzMapper接口中添加方法
/**
* 根据id查询班级信息
* @param id
*/
Clazz selectById(@Param("id") Long id);
第三处:在ClazzMapper.xml文件中进行配置
<select id="selectById" resultType="com.study.pojo.Clazz">
select * from t_clazz where cid=#{id}
</select>
逻辑如下:
执行结果,可以很明显看到先后有两条sql语句执行:
一对多
问题的引出
假设我们要去查一个班级的信息,包括班级的名字,班号以及这个班级的的所有学生。这就是一对多,一个班级对应多个学生。这个需求的话我们在mysql中查询的语句如下:
SELECT * FROM t_clazz
LEFT JOIN t_student
ON t_clazz.`cid`=t_student.`cid`
WHERE t_clazz.`cid`=2101
查询结果:
这个时候就要在Clazz类中添加List<Student> stus 属性。
@Data
public class Clazz {
private Long cid;
private String cname;
List<Student> stus;
}
collection处理
ClazzMappe编写r接口
/**
* 根据班级编号查询班级信息。同时班级中所有的学生信息也要查询。
* @param cid
* @return
*/
Clazz selectClazzAndStusByCid(@Param("cid") Long cid);
ClazztMapper.xml中实现
<resultMap id="clazzResultMap" type="com.study.pojo.Clazz">
<id property="cid" column="cid"></id>
<result property="cname" column="cname"></result>
<collection property="stus" ofType="com.study.pojo.Student">
<id property="sid" column="sid"></id>
<result property="sname" column="sname"></result>
</collection>
</resultMap>
<select id="selectClazzAndStusByCid" resultMap="clazzResultMap">
SELECT * FROM t_clazz
LEFT JOIN t_student
ON t_clazz.`cid`=t_student.`cid`
WHERE t_clazz.`cid`=#{cid}
</select>
测试代码
@Test
public void test01(){
SqlSession session = SqlSessionUtil.openSession();
ClazzMapper mapper = session.getMapper(ClazzMapper.class);
Clazz clazz = mapper.selectClazzAndStusByCid(2101L);
System.out.println(clazz);
}
分步查询
这个过程同样可以分为俩步:
第一步根据cid在班级表中查询cname
第二步根据cid在学生表中查询每个学生的sid sname
具体实施
ClazzMapper.xml中修改
<resultMap id="clazzResultMap" type="com.study.pojo.Clazz">
<id property="cid" column="cid"></id>
<result property="cname" column="cname"></result>
<collection property="stus"
select="com.study.mapper.StudentMapper.selectByCid"
column="cid">
</collection>
</resultMap>
<select id="selectClazzAndStusByCid" resultMap="clazzResultMap">
select * from t_clazz where cid=#{cid}
</select>
StudentMapper接口
/**
* 根据班级编号获取所有的学生。
* @param cid
* @return
*/
List<Student> selectByCid(@Param("cid") Long cid);
StudentMapper.xml
<select id="selectByCid" resultType="com.study.pojo.Student">
select * from t_student where cid=#{cid}
</select>
延迟加载解读
什么是延迟加载?
延迟加载也称为懒加载、惰性加载,使用延迟加载可以提高程序的运行效率,针对数据持久层的操作,在某些特定查询的情况下去访问特定的数据库,在其他情况下可以不访问某些数据表,尽量减少 SQL 的执行,从而达到提高速度的目的,是对数据库操作的一种优化。
说明:延迟加载只存在于分步查询
在mybatis中怎么开启延迟加载呢?
局部开启:
在association或者collection标签中添加fetchType="lazy"。
注意:默认是没有开启延迟加载的,而且这种在association或者collection中设置
延迟加载的方式,是局部的设置,只针对当前association或者collection所关联的SQL语句起作用。
测试代码
@Test
public void test01(){
SqlSession session = SqlSessionUtil.openSession();
ClazzMapper mapper = session.getMapper(ClazzMapper.class);
Clazz clazz = mapper.selectClazzAndStusByCid(2101L);
//没有用到stus属性
System.out.println(clazz.getCid());
System.out.println(clazz.getCname());
}
运行结果
我们可以很明显的看到延迟加载以后,只执行了一条sql语句
全局开启:
可以在mybatis核心配置文件中开启全局设置
在开发中大部分情况是需要用到延迟加载的,所以建议开启全局的延迟加载机制
在mybatis核心配置文件中添加<setting name="lazyLoadingEnabled" value="true"/>
实际中的开发模式:
把全局延迟加载打开。
如果某一步不需要延迟加载,设置fetchType="eager"。