现在根据设计模型建立对应的pojo
首先看体检表,由于体检表分为男性和女性,因此可以先设计一个父类,然后通过继承的方式来完成pojo
package com.learn.ssm.chapter5.pojo;
//体检表父类
public abstract class HealthForm {
@Override
public String toString() {
return "HealthForm [id=" + id + ", empId=" + empId + ", heart=" + heart
+ ", liver=" + liver + ", spleen=" + spleen + ", lung=" + lung
+ ", kidney=" + kidney + ", note=" + note + "]";
}
private int id;
private int empId;
private String heart;
private String liver;
private String spleen;
private String lung;
private String kidney;
private String note;
女性体检表
//女性体检表
public class FemaleHealthForm extends HealthForm{
private String uterus;
public String getUterus() {
return uterus;
}
@Override
public String toString() {
return super.toString()+ "FemaleHealthForm [uterus=" + uterus + "]";
}
public void setUterus(String uterus) {
this.uterus = uterus;
}
男性体检表
//男性体检表
public class MaleHealthForm extends HealthForm {
@Override
public String toString() {
return super.toString()+ "MaleHealthForm [prostate=" + prostate + "]";
}
private String prostate;
public String getProstate() {
return prostate;
}
public void setProstate(String prostate) {
this.prostate = prostate;
}
接下来设计员工表,工牌表,和任务表的pojo
//工牌表
public class WorkCard {
private int id;
private int empId;
private String realName;
private String department;
private String mobile;
private String position;
private String note;
任务表
public class Task {
//任务表
private int id;//编号
@Override
public String toString() {
return "Task [id=" + id + ", title=" + title + ", context=" + context
+ ", note=" + note + "]";
}
private String title;//任务标题
private String context;//任务内容
private String note;//备注
还剩雇员表和雇员任务表,它们有一定的关联。先从雇员任务表下手,雇员任务表是通过任务编号(task_id)和任务一一对应。
public class EmployeeTask {
//雇员任务表
/**
* 雇员任务表示通过任务编号task_id来和任务表进行一一关联的,这里只考虑其自身和任务编号的关联
*
*/
private int id;
private int empId;
private Task task=null;
private String taskName;
private String note;
属性task是一个Task类的对象,由它进行关联任务信息。设置雇员表是关键。雇员根据性别分为男雇员和女雇员。它们会有不同体检表记录,但是无论男,女都有一个雇员类,它有两个子类,男雇员类和女雇员类。在mybatis中,有一个鉴别器,通过雇员的字段sex来判断决定使用哪一个具体的子类(MaleEmployee和FemaleEmployee)初始化对象,它与工牌表示一一对应的关联关系,对于雇员任务表示一对多的关系。
雇员类POJO
/***
* 雇员父类
* 雇员根据性别分为男雇员和女雇员,他们会有不同的体检表,但是都有一个父类表。有两个子类(MaleEmployee男雇员)(FemaleEmploee女雇员)
* @author Administrator
*
*/
public class Employee {
private int id;
private String realName;
private SexEnum sex=null;
private Date birthday;
private String mobile;
private String email;
private String position;
private String note;
//工牌按一对一级联
private WorkCard workCard;
//雇员任务表,一对多的级联
private List<EmployeeTask> employeeTaskList=null;
男雇员类
//男性雇员表
public class MaleEmployee extends Employee {
private MaleHealthForm maleHealthForm=null;
public MaleHealthForm getMaleHealthForm() {
return maleHealthForm;
}
public void setMaleHealthForm(MaleHealthForm maleHealthForm) {
this.maleHealthForm = maleHealthForm;
}
女雇员表POJO
public class FemaleEmployee extends Employee{
//女性雇员表包括体检表
private FemaleHealthForm femaleHealthForm=null;
public FemaleHealthForm getFemaleHealthForm() {
return femaleHealthForm;
}
@Override
public String toString() {
return "FemaleEmployee [femaleHealthForm=" + femaleHealthForm + "]";
}
public void setFemaleHealthForm(FemaleHealthForm femaleHealthForm) {
this.femaleHealthForm = femaleHealthForm;
}
MaleEmployee和FemaleEmployee都继承了Employee类,有着不同体检表。Employee类是通过了employeeTaskList属性和多个雇员任务进行一对多级联。而工牌表则是通过workcard来进行一对一级联。
这样就完成了所有的POJO的设计
配置映射文件:
配置映射文件是级联的核心内容,而对于Mapper对的接口就不再书里给出了,因为根据映射文件编写接口十分简单,从最简单的内容入手,最简单的内容无非是那些关联最少的POJO,根据图5-2所示,4个POJO中task和workcard是星湖独立的。所以他们的映射文件相对简单
TaskMapper.xml&TaskMapper
TaskMapper
import com.learn.ssm.chapter5.pojo.Task;
public interface TaskMapper {
public Task getTask(int id);
}
TaskMapper.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- 查询任务表 -->
<mapper namespace="com.learn.ssm.chapter5.mapper.TaskMapper">
<select id="getTask" parameterType="int" resultType="task" >
select id,title,context,note from t_task where id=#{id}
</select>
</mapper>
workcard.xml&workcardMapper
package com.learn.ssm.chapter5.mapper;
import com.learn.ssm.chapter5.pojo.WorkCard;
public interface WorkCardMapper {
public WorkCard getWorkCardByEmpId(int id );
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- 查询工牌表 -->
<mapper namespace="com.learn.ssm.chapter5.mapper.WorkCardMapper">
<select id="getWorkCardByEmpId" parameterType="int" resultType="workCard" >
SELECT id, emp_id as empId, real_name as realName, department, mobile, position, note FROM t_work_card
where emp_id = #{empId}
</select>
</mapper>
这样就完成了两张表的映射文件。雇员任务表通过了任务编号(task_id)和任务表关联。这是一个一对一级联的关系。使用了association元素。雇员任务表一对一级联
雇员任务表一对一级联
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.learn.ssm.chapter5.mapper.EmployeeTaskMapper" >
<resultMap type="employeeTask" id="employeeTaskMap">
<id column="id" property="id"/>
<result column="emp_id" property="empId" />
<result column="task_name" property="taskName" />
<result column="note" property="note" />
<!-- 级联一对一association
association元素代表着一对一元素级联的开始,property属性代表着 映射到POJO属性上,select配置是命名空间+SQL.ID的形式,这样皆可以指定
对应Mapper的SQL,mybatis就会通过对应的SQL将数据查询回来。column代表SQL的列,作为参数传递给select属性指定的SQL,如果是多个属性则用逗号隔开
-->
<association property="task" column="task_id" select="com.learn.ssm.chapter5.mapper.TaskMapper.getTask"
/>
</resultMap>
<select id="getEmployeeTaskByEmpId" parameterType="int" resultMap="employeeTaskMap">
select id,emp_id,task_name,task_id,note from t_employee_task
where emp_id=#{empId}
</select>
</mapper>
这里重点讲解一下association的几种不同用法
<association property="task" column="task_id" select="com.learn.ssm.chapter5.mapper.TaskMapper.getTask" />
第一种:
association的元素代表着一对一级联的开始,property属性代表映射到POJO属性上,select配置是命名空间+SQL id的形式,这样就可以指向对应的mapper的SQL。MyBatis就会通过对应的SQL将数据查询回来。column代表SQL的列,用作参数传递给select属性指定的SQL,如果是多个参数,则需要使用逗号隔开。
第二种:(不使用association标签的方式)
<select id="getEmployeeWithDeptById0" resultMap="employeeDept0">
select e.id id, e.name name, e.gender gender, e.email email, e.d_id departmentId, d.department_name departmentName
from tbl_employee e, tbl_department d
where d.id=e.d_id and e.id=#{id}
</select>
<!-- 第一种:利用resultMap进行级联查询,不使用association标签-->
<resultMap id="employeeDept0" type="com.hly.entity.Employee">
<id column="id" property="id"></id>
<result column="name" property="name"></result>
<result column="gender" property="gender"></result>
<result column="email" property="email"></result>
<result column="departmentId" property="department.id"></result>
<result column="departmentName" property="department.departmentName"></result>
</resultMap>
第三种:使用association标签+javaType属性
这种方法个人感觉跟第一种没有本质上的区别,还是一条sql语句对两张表进行关联查询,只不过在结果集映射的时候有一些不同,引入了association标签。可读性比较好,对象的结构关系相较于第一种方式来说更为清晰和明朗。
sql部分,与第一种无异:
<select id="getEmployeeWithDeptById" resultMap="employeeDept">
select e.id id, e.name name, e.gender gender, e.email email, e.d_id departmentId, d.department_name departmentName
from tbl_employee e, tbl_department d
where d.id=e.d_id and e.id=#{id}
</select>
<!-- 第二种:利用resultMap进行级联查询,使用association标签 -->
<resultMap id="employeeDept" type="com.hly.entity.Employee">
<id column="id" property="id"></id>
<result column="name" property="name"></result>
<result column="gender" property="gender"></result>
<result column="email" property="email"></result>
<association property="department" javaType="com.hly.entity.Department">
<id column="departmentId" property="id"></id>
<result column="departmentName" property="departmentName"></result>
</association>
</resultMap>
在级联元素中,association中是通过javaType的定义去声明实体映射,可以看到在这种写法中,通过association标签明确指定了department对象的类型,然后在这个association的子标签中对department对象进行结果映射
而前面使用association标签+select属性
这种方法就有意思了。与前面两种写法有比较大的不同,使用association的select标签,可以将原本两表联查的一条sql语句拆分为两条简单的sql语句。个人以为搞出这种方式的原因就是要支持级联查询的懒加载吧,这样可以很好的提升数据库的性能,毕竟只有在用到关联对象相关属性的时候,才会执行第二步的查询操作。这部分内容等到后面了解其原理,看过源码后再回来详细说明,在此留一个根。
sql部分,这里就分两部分了。第一是在t_mployee_task表中,根据id查出对应的记录。第二步就是根据前一步中查出的task_id的值,在task表中查询对应的记录。注意这两个sql是分散在两个mapper.xml中的哈。
association标签中有两个重要的属性,select是用来指定这个对象怎么去查,而column属性则是从第一步的查询结果中找出select所需的查询参数。
再研究一下体检表,它能拆分为男性雇员表和女性雇员表,所以就有两个简单的映射器。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.learn.ssm.chapter5.mapper.MaleHealthFormMapper" >
<select id="getMaleHealthForm" parameterType="int" resultType="maleHealthForm" >
select id, heart, liver, spleen, lung, kidney, prostate, note from
t_male_health_form where emp_id= #{id}
</select>
</mapper>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.learn.ssm.chapter5.mapper.FemaleHealthFormMapper" >
<select id="getFemaleHealthForm" parameterType="int" resultType="femaleHealthForm" >
select id, heart, liver, spleen, lung, kidney, uterus, note from
t_female_health_form where emp_id = #{id}
</select>
</mapper>
<!-- 这两个映射器都是通过雇员编号找到对应的体检表的记录,为雇员查询是提供了查询体检表的SQL-->
这两个映射器都是主要通过雇员编号找到对应的映射关系,为雇员查询是提供了查询的体检表SQL
现在创建雇员的映射关系
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.learn.ssm.chapter5.mapper.EmployeeMapper">
<resultMap type="employee" id="employee">
<id column="id" property="id" />
<result column="real_name" property="realName"/>
<!-- 第二种方式显式注册自定义typehandler -->
<result column="sex" property="sex" typeHandler="com.learn.ssm.chapter4.typehandler.SexTypeHandler"/>
<result column="birthday" property="birthday" />
<result column="mobile" property="mobile" />
<result column="email" property="email" />
<result column="position" property="position" />
<result column="note" property="note" />
<!-- 一对一工牌 这样就输出信息啦-->
<association property="workCard" column="id" select="com.learn.ssm.chapter5.mapper.WorkCardMapper.getWorkCardByEmpId" >
</association>
<!-- 一对多的任务表,通过雇员任务表的雇员编号,返回任务list -->
<collection property="employeeTaskList" column="id" fetchType="eager"
select="com.learn.ssm.chapter5.mapper.EmployeeTaskMapper.getEmployeeTaskByEmpId"
>
</collection>
<!--鉴别器 -->
<discriminator javaType="int" column="sex">
<case value="1" resultMap="maleHealthFormMapper" />
<case value="0" resultMap="femaleHealthFormMapper" />
</discriminator>
</resultMap>
<resultMap type="femaleEmployee"
id="femaleHealthFormMapper" extends="employee" >
<!--男女性的雇员表继承了resultmap的id为employee,从类上来说也确实是继承 -->
<association property="femaleHealthForm" column="id" select="com.learn.ssm.chapter5.mapper.FemaleHealthFormMapper.getFemaleHealthForm" />
</resultMap>
<resultMap type="maleEmployee" id="maleHealthFormMapper" extends="employee" >
<association property="maleHealthForm" column="id" select="com.learn.ssm.chapter5.mapper.MaleHealthFormMapper.getMaleHealthForm" />
</resultMap>
<!--工牌 -->
<resultMap type="workCard" id="inworkcard" >
</resultMap>
<select id="getEmployee" parameterType="int" resultMap="employee" >
select id,real_name as realName,sex,birthday,mobile,email,position,note from t_employee where id=#{id}
</select>
注意:
- associaation元素:对工牌进行一对一级联,这个在雇员任务表中已经分析过
- collection元素 一对多级联,其select元素指向SQL,将通过column制定的SQL字段作为参数进行传递,然后就将结果返回给雇员POJO的属性employeeTaskList
- discriminator元素,鉴别器,它的属性column代表着使用哪个字段来进行鉴别,这里的sex,而它的子元素case,则用于区分。类似于switch...case语句,而resultMap属性表示采用哪个ResultMap去映射,比如sex=1,则使用maleHealthFormMapper进行映射。没有合适的case,使用employee进行映射
测试代码:
public static void testGetEmployee() {
Logger logger=Logger.getLogger(chapter5Main.class);
SqlSession sqlSession = null;
try {
sqlSession = SqlSessionFactoryUtils.openSqlSession();
EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);
Employee employee = employeeMapper.getEmployee2(1);
// EmployeeTaskMapper employeeTaskMapper=sqlSession.getMapper(EmployeeTaskMapper.class);
// List<EmployeeTask> employeeTask=employeeTaskMapper.getEmployeeTaskByEmpId(2);
// TaskMapper taskmapper=sqlSession.getMapper(TaskMapper.class);
// Task task=taskmapper.getTask(1);
// logger.info(employee.getEmployeeTaskList());
// System.out.println(employee.getEmployeeTaskList());
System.out.println(employee);
} catch(Exception ex) {
ex.printStackTrace();
} finally {
if (sqlSession != null) {
sqlSession.close();
}
}
}
延迟加载:
配置项 | 作用 | 配置选项说明 | 默认值 |
---|---|---|---|
lazyLoadingEnabled | 延迟加载的全局开关,当开启时,所有关联对象都会延迟加载,在特定关联关系中,可通过设置fetchType属性来覆盖该项的开关状态 | true\false | false |
aggressiveLazyLoading | 当启用时,对任意延迟属性的调用会使带有延迟加载属性的对象完整加载;反之,则每种属性按需加载 | true\false | 版本之前为true,之后为false |
在mybatisconfig.xml中添加如下代码:
<settings >
<setting name="lazyLoadingEnabled" value="true" ></setting>
<setting name="aggressiveLazyLoading" value="false" ></setting>
</settings>
选项lazyLoadingEnabled决定是否开启延迟加载,而选项aggressiveLazyLoading则控制是否采用层级加载,采用层级加载的话,所有关联的信息同个层级的都会被加载出来。比如查询雇员信息,属性中的task关联雇员任务表,属性workcard关联工卡等等,这些是处于同一个层级的情况下。
我们要加载雇员信息只加载雇员任务信息,但是因为层级加载会把工牌信息也加载进来,为了处理这个问题我们可以使用fetchType的属性,它可以全局定义无法处理的问题。fetchType存在级联元素collection,association中。有两个值
- eager,获得当前的POJO后,立即加载对应数据
- lazy 获得当前POJO后延迟加载对应的数据
现在全面学习另一种级联,这个方式完全可以消除N+1的问题,但是也引发其他的问题,首先SQL比较复杂,其次所需要的配置比之前复杂的多。再次一次性将所有的数据提取出来会造成内存的浪费,一般用于比较简单的且关联不多的场景
<select id="getEmployee2" parameterType="int" resultMap="employee2" >
select
emp.id, emp.real_name, emp.sex, emp.birthday,
emp.mobile, emp.email,
emp.position, emp.note,
et.id as et_id, et.task_id as et_task_id,
et.task_name as et_task_name,
et.note as et_note,
if (emp.sex = 1,
mhf.id, fhf.id) as h_id,
if (emp.sex = 1, mhf.heart, fhf.heart) as
h_heart,
if (emp.sex = 1, mhf.liver, fhf.liver) as h_liver,
if (emp.sex
= 1, mhf.spleen, fhf.spleen) as h_spleen,
if (emp.sex = 1, mhf.lung,
fhf.lung) as h_lung,
if (emp.sex = 1, mhf.kidney, fhf.kidney) as
h_kidney,
if (emp.sex = 1, mhf.note, fhf.note) as h_note,
mhf.prostate
as h_prostate, fhf.uterus as h_uterus,
wc.id wc_id, wc.real_name
wc_real_name, wc.department wc_department,
wc.mobile wc_mobile,
wc.position wc_position, wc.note as wc_note,
t.id as t_id, t.title as
t_title, t.context as t_context, t.note as t_note
from t_employee emp
left join t_employee_task et on emp.id = et.emp_id
left join
t_female_health_form fhf on emp.id = fhf.emp_id
left join
t_male_health_form mhf on emp.id = mhf.emp_id
left join t_work_card wc
on emp.id = wc.emp_id
left join t_task t on et.task_id = t.id
where
emp.id =#{id}
</select>
这里的SQL我们通过left join语句,将一个雇员模型信息所有的关联起来,这样便可以通过一条SQL将所有的信息都查询出来。对于列名做出了别名的处理。在mybatis中允许对这样的SQL进行配置,来完成级联。
<resultMap id="employee2" type="employee" >
<id column="id" property="id" />
<result column="real_name" property="realName"/>
<!-- 第二种方式显式注册自定义typehandler -->
<result column="sex" property="sex" typeHandler="com.learn.ssm.chapter4.typehandler.SexTypeHandler"/>
<result column="birthday" property="birthday" />
<result column="mobile" property="mobile" />
<result column="email" property="email" />
<result column="position" property="position" />
<result column="note" property="note" />
<!--在级联中assocaiation是通过javaType去声明实体映射,而collection则是通过ofType进行声明 -->
<association property="workCard" column="id" javaType="workCard" >
<id column="wc_id" property="id" ></id>
<result column="wc_real_name" property="realName" />
<result column="id" property="empId" />
<result column="wc_department" property="department" />
<result column="wc_mbile" property="mobile" />
<result column="wc_position" property="position" />
<result column="wc_note" property="note" />
</association>
<collection property="employeeTaskList" ofType="employeeTask" column="id">
<id column="et_id" property="id" />
<result column="id" property="empId" />
<result column="et_task_name" property="taskName" />
<result column="et_note" property="note" />
<association property="task" javaType="task"
column="et_task_id">
<id column="t_id" property="id" />
<result column="t_title" property="title" />
<result column="t_context" property="context" />
<result column="t_note" property="note" />
</association>
</collection>
<discriminator javaType="int" column="sex" >
<case value="1" resultMap="maleHealthFormMapper2"></case>
<case value="0" resultMap="femaleHealthFormMapper2"></case>
</discriminator>
</resultMap>
<resultMap type="maleEmployee" id="maleHealthFormMapper2" extends="employee2" >
<association property="maleHealthForm" column="id" javaType="maleHealthForm" >
<id column="h_id" property="id" />
<result column="h_heart" property="heart" />
<result column="h_liver" property="liver" />
<result column="h_spleen" property="spleen" />
<result column="h_lung" property="lung" />
<result column="h_kidney" property="kidney" />
<result column="h_prostate" property="prostate" />
<result column="h_note" property="note" />
</association>
</resultMap>
<resultMap type="femaleEmployee" id="femaleHealthFormMapper2" extends="employee2" >
<association property="femaleHealthForm" column="id" javaType="femaleHealthForm" >
<id column="h_id" property="id" />
<result column="h_heart" property="heart" />
<result column="h_liver" property="liver" />
<result column="h_spleen" property="spleen" />
<result column="h_lung" property="lung" />
<result column="h_kidney" property="kidney" />
<result column="h_uterus" property="uterus" />
<result column="h_note" property="note" />
</association>
</resultMap>
- 每一个级联元素(association,discriminator,collection)中属性的id的配置和POJO实体配置的id一一对应,形成级联,比如上述的SQL列et_task_id和task实体的id是对应的,这是级联的关键所在。
-在级联元素上,association是通过javaType的定义声明实体映射,而collection则是使用ofType进行声明 - discriminator元素定义使用何种具体的resultMap进行级联,这里通过sex列进行判定
多对多级联
在现实生活中,有一种多对多的级联,而在程序中多对多的级联往往会被拆分成两个一对多级联处理
比如说:有许多用户,用户归属于一些角色,这样一个用户可以对应多个角色,而一个角色有可以由多个用户担当。
角色POJO
public class Role2 {
private Long id;
private String roleName;
private String note;
// 关联用户信息,一对多关联
private List<User2> userList;
用户POJO
public class User2 {
private Long id;
private String userName;
private String realName;
private SexEnum sex;
private String moble;
private String email;
private String note;
// 对角色一对多关联
private List<Role2> roleList;
两个List类型的属性是专门做一对多级联的时候使用的,使用collection的元素去完成,得到两个mapper
角色mapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ssm.chapter5.mapper2.RoleMapper2">
<resultMap type="com.ssm.chapter5.pojo2.Role2" id="roleMapper">
<id column="id" property="id" />
<result column="role_name" property="roleName" />
<result column="note" property="note" />
<collection property="userList" column="id" fetchType="lazy"
select="com.ssm.chapter5.mapper2.UserMapper2.findUserByRoleId" />
</resultMap>
<select id="getRole" parameterType="long" resultMap="roleMapper">
select id, role_name, note from t_role where id = #{id}
</select>
<select id="findRoleByUserId" parameterType="long" resultMap="roleMapper">
select r.id, r.role_name, r.note from t_role r, t_user_role ur
where r.id = ur.role_id and ur.user_id = #{userId}
</select>
</mapper>
用户mapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ssm.chapter5.mapper2.UserMapper2">
<resultMap type="com.ssm.chapter5.pojo2.User2" id="userMapper">
<id column="id" property="id" />
<result column="user_name" property="userName" />
<result column="real_name" property="realName" />
<result column="sex" property="sex"
typeHandler="com.ssm.chapter5.typeHandler.SexTypeHandler" />
<result column="mobile" property="moble" />
<result column="email" property="email" />
<result column="position" property="position" />
<result column="note" property="note" />
<collection property="roleList" column="id" fetchType="lazy"
select="com.ssm.chapter5.mapper2.RoleMapper2.findRoleByUserId" />
</resultMap>
<select id="getUser" parameterType="long" resultMap="userMapper">
select id, user_name, real_name, sex, moble, email, note from t_user where
id =#{id}
</select>
<select id="findUserByRoleId" parameterType="long" resultMap="userMapper">
select u.id, u.user_name, u.real_name, u.sex, u.moble, u.email, u.note
from
t_user u , t_user_role ur where u.id = ur.user_id and ur.role_id =#{roleId}
</select>
</mapper>
这里使用collection去关联,但是把fetchType设为laz,这样就能够进行延迟加载。
测试代码
public static void testUserRole() {
SqlSession sqlSession = null;
try {
sqlSession = SqlSessionFactoryUtils.openSqlSession();
RoleMapper2 roleMapper2 = sqlSession.getMapper(RoleMapper2.class);
Role2 role2 = roleMapper2.getRole(1L);
System.out.println(role2.getUserList().size());
UserMapper2 userMapper2 = sqlSession.getMapper(UserMapper2.class);
User2 user2 = userMapper2.getUser(1L);
System.out.println(user2.getRoleList().size());
} catch(Exception ex) {
ex.printStackTrace();
} finally {
if (sqlSession != null) {
sqlSession.close();
}
}
}
一共有3条SQL被执行,因为在role.getUserList的方法中调用获取用户信息,所以延迟加载的语句被执行。