SSM框架下,mapper.xml 中 association 标签和 collection标签的使用
当数据库中表与表之间有关联时,在对数据库进行操作时,就不只是针对某一张表了,需要联表查询
MyBatis中如何实现联表查询
1、首先新建两张表
学生表(student)
ID:stu_id
姓名:stu_name
年龄:stu_age
性别:stu_gender
所在班级:g_id
班级表(grade)
ID:g_id
班级名称:g_name
学生表和班级表通过 g_id进行关联,一个班级对应多个学生
2、创建相应的实体类和mapper接口
(1)创建 Student类和 Grade 类(包名:com.bwlu.bean)
(2)创建 StudentMapper 接口和 GradeMapper 接口和相应的 XML 文件(使用逆向生成可直接生成)
StudentMapper.java 接口
Student selectByPrimaryKey(Integer stuId);//按主键查询一条记录
StudentMapper.xml
select stu_id, stu_name, stu_age, stu_gender, g_id from student
where stu_id = #{stuId,jdbcType=INTEGER}
GradeMapper.java
Grade selectByPrimaryKey(Integer gId);//按主键查询一条记录
GradeMapper.xml
select g_id, g_name from grade
where g_id = #{gId,jdbcType=INTEGER}
3、在sql映射文件中写映射sql语句【联合查询:级联属性封装结果集】
3.1第一种
(1)在 Student.java 中将 g_id 属性换成班级类型(Grade),并添加相应的getter和setter方法
//private Integer g_id;
privateGrade grade;publicGrade getGrade() {returngrade;
}public voidsetGrade(Grade grade) {this.grade =grade;
}
(2)在 xml 中封装结果集,并编写相应的 sql 语句
select stu_id, stu_name, stu_age, stu_gender, g.g_id, g_name
from student s,grade g
where s.g_id = g.g_id AND stu_id = #{stuId,jdbcType=INTEGER}
(3)测试
@AutowiredprivateStudentMapper studentMapper;
@Testpublic voidtestAssociation() {
Student student= studentMapper.selectByPrimaryKey(6);
System.out.println(student);//Student [stuId=6, stuName=lixiang, stuAge=22, stuGender=1, grade=Grade [gId=3, gName=软件(3)班]]
}
3.2第二种
(1)在 Student.java 中将 g_id 属性换成班级类型(Grade),并添加相应的getter和setter方法,同 3.1 的(1)
(2)使用association来定义关联对象的规则【比较正规的,推荐的方式】
select stu_id, stu_name, stu_age, stu_gender, g.g_id, g_name
from student s,grade g
where s.g_id = g.g_id AND stu_id = #{stuId,jdbcType=INTEGER}
(3)测试(同 3.1的(3),结果也一样)
3.3第三种
(1)在 Student.java 中将 g_id 属性换成班级类型(Grade),并添加相应的getter和setter方法,同 3.1 的(1)
(2)使用Association进行分步查询【上述结果相当于使用嵌套结果集的形式】
select g_id, g_name from grade
where g_id = #{gId,jdbcType=INTEGER}
select stu_id, stu_name, stu_age, stu_gender, g_id
from student
where stu_id = #{stuId,jdbcType=INTEGER}
注:使用 resultType 返回值类型进行接收,必须使用驼峰式命名,使数据库中的字段和实体类中的字段对应。
(3)测试(同 3.1的(3),结果也一样)
(2)中也可以指定为GradeMapper 下的方法。
懒加载机制【按需加载,也叫懒加载】
在 3.3 分步查询中,每次查询 Student对象的时候,都将关联 Grade 的对象查询出来了。
使用延迟加载,可以在需要 班级 信息的时候,再去查询,不需要的时候就不用查询。
在 MyBatis 的全局配置文件中,加入两个配置
这样,当我们查询 Student对象的时候,
如果只输出学生姓名,就不会执行查询班级信息的 sql 语句(只执行一条 sql 语句),
select stu_id, stu_name, stu_age, stu_gender, g_id from student where stu_id = ? Parameters: 6(Integer)
当需要班级信息的时候才会执行,(执行两条 sql 语句)
select stu_id, stu_name, stu_age, stu_gender, g_id from student where stu_id = ? Parameters: 6(Integer)
select g_id, g_name from grade where g_id = ? Parameters: 3(Integer)
3.4 上述是在多端(学生)查询一端(班级)的信息,用 association,当我们在一端查询多端信息的时候,需要使用 collection,查出的是一个集合
(1)在班级类(Grade)类中添加一个属性List stuList,并添加相应的 getter 和 setter 方法
private ListstuList;public ListgetStuList() {returnstuList;
}public void setStuList(ListstuList) {this.stuList =stuList;
}
(2)使用collection标签定义关联的集合类型元素的封装规则【collection:嵌套结果集的方式】
select g.g_id, g_name, stu_id, stu_name, stu_age, stu_gender
from grade g,student s
where g.g_id = s.g_id AND g.g_id = #{gId,jdbcType=INTEGER}
(3)测试
@AutowiredprivateGradeMapper gradeMapper;
@Testpublic voidtestCollection() {
Grade grade= gradeMapper.selectByPrimaryKey(3);
List stuList =grade.getStuList();for(Student stu:stuList){
System.out.println(stu);//Student [stuId=3, stuName=fenghen, stuAge=12, stuGender=1, grade=null]//Student [stuId=6, stuName=lixiang, stuAge=22, stuGender=1, grade=null]
}
}
注意:grade为null,因为 Student和 Grade相互嵌套,如果用 resultMap进行接收的话,会相互嵌套,最终导致栈溢出,应用 resultType 进行接收,嵌套的类型为 null 值。
3.5 使用分步查询结果集的方式
(1)在班级类(Grade)类中添加一个属性List stuList,并添加相应的 getter 和 setter 方法,同 3.4 中的(1)
(2)在 GradeMapper.xml 中添加如下方法
select g_id, g_name from grade
where g_id = #{gId,jdbcType=INTEGER}
在 StudentMapper.xml 中添加如下方法 selectByGId :根据 g_id 查询学生集合
select
stu_id, stu_name, stu_age, stu_gender,g_id
from student
where g_id = #{gId,jdbcType=INTEGER}
(3)测试(同 3.4的(3),结果也一样)