文章目录
关联属性的封装(连接查询 & 分步查询),延迟加载
在项目中,不可避免的存在着类与类之间的关联,在数据库的表中,这样的关联使用关联属性的主键表示;但在对象中,被关联的属性一般是以对象的形式存在。
举个例子:
学生Student
和学院College
是多对一的关系,在这里,学生类可以有一个字段,用来存储他/她所在的学院。
public class Student {
Integer id;
String name;
College college;
}
使用连接查询
使用连接查询获得college,并且封装到student对象中
public Student getStudentById(Integer id);
<select id="getStudentById" resultMap="student">
select *
from student, college
where studet.stuent_college = college.college_id
and student_id = #{id}
</select>
有了查询的结果,显然Mybatis不能自动封装,需要根据我们配置的reslutMap
进行封装。
方式一:嵌套封装
<resultMap id="student" type="com.test.entity.Student">
<id column="student_id" property="id"></id>
<result column="student_name" property="name"></result>
<!-- 封装college,经过连接查询,已经将对应的学院信息查询出来了 -->
<association property="college"><!--这里封装college这个bean-->
<id column="college_id" property="id"></id>
<result column="college_name" property="name"></result>
</association>
</resultMap>
方式二:级联属性
<resultMap id="student" type="com.test.entity.Student">
<id column="student_id" property="id"></id>
<result column="student_name" property="name"></result>
<!-- 封装college,经过连接查询,已经将对应的学院信息查询出来了 -->
<result column="college_id" property="college.id"></result>
<result column="college_name" property="college.name"></result>
</resultMap>
使用分步查询
分布查询也就是说,对于不同的表,不进行连接,而是分开查。
在这个例子中,可以先查询学生的信息,因为学生的信息中保存了college表中记录的主键,可以再根据这个主键查询college表,再将这次查询的结果封装到student对象的college字段。
public Student getStudentById(Integer id);
<select id="getStudentById" resultMap="student">
select * from student where student_id = #{id}
</select>
首先,第一次查询当前javabean的信息,它关联的对象,交给resultMap
查询,并且封装。
<resultMap id="student" type="com.test.entity.Student">
<id column="student_id" property="id"></id>
<result column="student_name" property="name"></result>
<association property="college" select="com.test.dao.ICollegeDao.getCollegeById" column="id=student_college">
<id property="id" column="college_id"></id>
<result property="name" column="college_name"></result>
</association>
</resultMap>
注意association
的属性:
property
:表示要封装的属性(与id和result的property属性一样)select
:用来指定一个查询的方法。这个属性指定一个已经配置好的<select/>
标签,通过"名称空间.id"
进行查找(名称空间找到对应的mapper配置,在这个配置中查找id指定的<select/>
)column
:这里的column表示传递给查询方法的参数。column和property属性配套使用,含义就是将column指定的列映射为property指定的属性,在分布查询时,这个映射过程还需要经过一次查询,通过select值得顶查询的方式,而column正好是select的参数
column
传递参数时,使用键值对的方式"id=student_college"
,这个键值对的含义就是,将student_college
这一列的值,作为参数id
的值,传递给select方法。如果select方法接收多个参数,键值对通过都好隔开。
延迟加载
延迟加载是很强大很有用的功能,当我们仅需要学生的信息,而不需要他的学院信息,这时后,就没必要将他所在的学院封装到学生的bean。
首先,可以想到的就是再写一个方法,让他不封装college。
另一个解决方法,就是使用延迟加载。延迟加载就是在使用时,才查表,然后封装
也就是说,如果使用了延迟加载,我们通过分步查询的方式,当我们获取学生信息的时候,只会查一次学生表,当访问到college字段时,才会进行第二次查询,将结果封装到college。
开启延迟加载方式一:全局配置
在全局配置文件中,进行下面的配置
<settings>
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="aggressiveLazyLoading" value="false" />
</settings>
开启延迟加载方式二:association
标签的fetchType
属性
应用官方文档
可选的。有效值为 lazy 和 eager。 指定属性后,将在映射中忽略全局配置参数 lazyLoadingEnabled,使用属性的值。
lazy
:延迟加载(懒汉式)eager
:非延迟加载(饿汉式)
<resultMap id="student" type="com.test.entity.Student">
<id column="student_id" property="id"></id>
<result column="student_name" property="name"></result>
<association property="college" select="com.test.dao.ICollegeDao.getCollegeById" column="id=student_college" fetchType="lazy">
<id property="id" column="college_id"></id>
<result property="name" column="college_name"></result>
</association>
</resultMap>