一、简介:
关联查询主要用于多表查询,数据库表与表之间存在关系,同样的类与类之间也存在关系,关联映射就是通过映射来描述这种关系,包括(一对一,一对多,多对多),mybatis 提供了高级的关联查询功能,可以很方便地将数据库获取的结果集映射到定义的Java Bean 。
二、使用:
关联查询主要包括俩个步骤:
1.修改实体类之间的关系。
2.映射文件里配置<resultMap>对查询结果集进行封装。写对应的SQL语句。
数据库表如下:
说明:一个班级对应一个老师 ,一个班级对应多个学生 teacherId 和 classId分布为外键
第一步:描述实体类之间的关系(持有对方当成自己的属性)
Classes:
public class Classes {
private Integer cid;
private String className;
private Teacher teacher; //一对一
private Set<Student> studentSet;//一对多
private Classes classes; //测试对同一表懒加载
//省略get set 下同
}
Teacher:
public class Teacher {
private Integer tid;
private String name;
//get set
}
Student:
public class Student {
private Integer sid;
private String name;
private Integer classId;
private Classes classes;
//get set
}
第二步:配置<resultMap>(关联查询主要是在<resultMap>元素中,用<association>配置一对多,用<collection>配置一对多)
ClassesMapper.xml
<resultMap id="ClassesTeaResultMap" type="Classes" ><!--这里设置了别名,所有直接可以使用类名-->
<id column="cid" jdbcType="INTEGER" property="cid"/>
<result column="className" jdbcType="VARCHAR" property="className"/>
<association property="teacher" javaType="Teacher"><!--持有的一个对象-->
<id column="tid" javaType="INTEGER" property="tid"/>
<result column="teacherName" jdbcType="VARCHAR" property="name"/>
</association>
</resultMap>
<select id="selectByPrimaryKey" resultMap="ClassesTeaResultMap" parameterType="java.lang.Integer" >
select c.cid,c.className,t.tid ,t.name as teacherName
from classes c,teacher t
where cid = #{cid,jdbcType=INTEGER} and c.teacherId = t.tid
</select>
<resultMap id="ClassesStuResultMap" type="Classes" >
<id column="cid" jdbcType="INTEGER" property="cid"/>
<result column="className" jdbcType="VARCHAR" property="className"/>
<collection property="studentSet" ofType="Student"><!--包含多个对象-->
<result column="name" property="name"/>
</collection>
</resultMap>
<select id="selectClassStuByPrimaryKey" resultMap="ClassesStuResultMap" parameterType="java.lang.Integer" >
select c.cid,c.className,s.name
from classes c,student s
where cid = #{cid,jdbcType=INTEGER} and s.classId = c.cid
</select>
说明:
- resultMap 里的id不能重复,对应select标签里面的resultMap属性值
- id 标签代表的是主键列
- result标签表示的是非主键列
- colunm 代表的是查询结果集的列名,有可能不是数据库中的列名(起别名)
- property 表示的是Java Bean的属性名
- javaType 为类名(没配置别名需要写包名+类名)
- association标签代表的是一的一方,比如一个班级的一个老师
- collection标签代表的多的一方,比如一个班级的多个学生 注意:ofType="Student" 而不是javaType
- select 标签注意SQL语句写法,这里采用的是表连接可以避免(N+1)问题,除非使用懒加载才会选择嵌套子查询。
- select 标签id对应接口的方法名字,不能重复
- ResultMap中conlum的数量与查询结果集个数相同
测试 :
说明:在测试前不要忘记将映射文件配置到mybatis配置文件中,采用接口方式调用方法要在接口写对应的方法名。
package org.lanqiao.dao;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.lanqiao.entity.Classes;
import org.lanqiao.entity.Student;
import java.io.IOException;
import java.io.Reader;
public class StudentMapperTest {
SqlSessionFactory sqlSessionFactory;
Reader reader;//读取配置文件
SqlSession session = null;
@Before
public void loadXml(){
try {
reader = Resources.getResourceAsReader("mybatis-Config.xml");
sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
session = sqlSessionFactory.openSession();
} catch (IOException e) {
e.printStackTrace();
}
}
@Test
public void testSelectStuClassByPrimaryKey() {
ClassesMapper classesMapper = session.getMapper(ClassesMapper.class);
Classes classes = classesMapper.selectByPrimaryKey(1);
System.out.println(classes.getClassName());
System.out.println(classes.getTeacher().getName());
System.out.println(classes.getTeacher().getTid());
}
@After
public void afterTest(){
if (reader !=null){
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (session !=null){
session.close();
}
}
}