情景:一个教师负责教多个学生。
站在学生的角度,学生对教师是多对一的关联关系;
站在教师的角度,教师对学生是一对多的集合关系。
需求:查询所有学生,及相关联的教师信息。
teacher表
student表
根据需求,学生表中的教师设为实体类,方便引用。
以下只列出实体类属性,自行添加 getter和 setter、构造方法等。
Teacher类
/**
* 教师ID
*/
private int id;
/**
* 教师姓名
*/
private String name;
public Teacher() {
}
Student类
/**
* 学生ID
*/
private int id;
/**
* 学生姓名
*/
private String name;
/**
* 关联教师
*/
private Teacher teacher;
先看看直接查询出来是什么结果,再分析该如何处理。
StudentMapper
/**
* 查询所有学生,以及关联教师信息
* @return 学生列表
*/
List<Student> listStudents();
StudentMapper.xml
<select id="listStudents" resultType="student">
select *
from mybatis.student;
</select>
注:
Mapper.xml
建议存放在resources目录下,与接口同级。MyBatis配置文件
中注册 Mapper
或Mapper.xml
!@Test
public void testListStudents() {
// 获取SqlSession实例
SqlSession sqlSession = MyBatisUtils.getSqlSession();
// 获取Mapper
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
// 执行方法
List<Student> students = mapper.listStudents();
for (Student student : students) {
System.out.println(student);
}
// 关闭连接
sqlSession.close();
}
查询结果:teacher为null
原因:
student
表,字段为tid
:关联教师的ID;Student
类,属性为teacher
:关联教师的对象引用(实现逻辑外键);多对一
的关系,即关联(association)
关系。站在学生的角度,学生对教师是多对一的关联关系。
有以下两种方法:
StudentMapper.xml
<select id="listStudents" resultMap="studentMap">
select id, name, tid
from mybatis.student;
</select>
<resultMap id="studentMap" type="student">
<!-- 数据库字段和实体类属性能自动映射,可以删去 -->
<result property="id" column="id"/>
<result property="name" column="name"/>
<!-- 学生对教师:一对多,是关联关系 -->
<association property="teacher" column="tid" javaType="teacher" select="getTeacherById"/>
</resultMap>
<select id="getTeacherById" resultType="teacher">
select id, name
from mybatis.teacher
where id = #{tid};
</select>
分析:
原本的select标签
中的resultType
已无法满足需求,所以应该用resultMap
结果映射。
创建一个resultMap
,用于处理数据库和实体类的映射关系:
result
标签:处理简单映射,若数据库字段和实体类属性能自动映射,无需显式配置;
property
:实体类的属性名;column
:数据库表的字段名。association
标签:处理复杂映射,代表一对多的关联关系;
property
:实体类的属性名;column
:数据库表的字段名;javaType
:属性的Java类型,使用全限类名或别名;select
:引用子查询语句,Teacher需要通过学生表的tid查出;相当于以下SQL语句:
select s.id as s_id,
s.name as s_name,
s.tid as t_id,
(select name
from teacher
where id = t_id)as t_name
from mybatis.student as s;
StudenMapper.xml
<select id="listStudents" resultMap="studentMap">
select s.id as s_id,
s.name as s_name,
s.tid as t_id,
t.name as t_name
from mybatis.student as s
left join mybatis.teacher as t
on s.tid = t.id
</select>
<resultMap id="studentMap1" type="student">
<result property="id" column="s_id"/>
<result property="name" column="s_name"/>
<association property="teacher" javaType="teacher">
<result property="id" column="t_id"/>
<result property="name" column="t_name"/>
</association>
</resultMap>
分析:
原本的select标签
中的resultType
已无法满足需求,所以应该用resultMap
结果映射;
创建一个resultMap
,用于处理数据库和实体类的映射关系:
resultMap
中配置。result
标签:处理简单映射,由于SQL语句中起了别名,所以需要显式配置;
property
:实体类的属性名;column
:数据库表的字段名。association
标签:处理复杂映射,代表一对多的关联关系;
property
:实体类的属性名;javaType
:属性的Java类型,使用全限类名或别名;column
和select
两个属性,但需要在内部配置result标签
,将查到的teacher的字段
映射到Teacher类的属性
上。相当于以下SQL语句:
select s.id as s_id,
s.name as s_name,
s.tid as t_id,
t.name as t_name
from mybatis.student as s
left join mybatis.teacher as t
on s.tid = t.id;
建议:使用联表查询!
子查询
student
表包含的属性:属于Student本身的属性
(id、name),跟Teacher有关的属性
(逻辑外键tid);resultMap
映射:tid
和teacher
;teacher表
的属性查出并封装到Teacher对象
中。联表查询
属于Student本身的属性
(id、name),跟Teacher有关的属性
(逻辑外键tid),并通过联表查询查出属于Teacher本身的属性
(name);resultMap
结果映射;resultMap
结果集映射:所有字段和属性。需求:查询一个教师,及包含的学生集合。
无需变动,同上。
根据需求:
需要查询一个教师及其包含学生的集合,所以为 Teacher类增加一个学生集合的属性。
不再那么关注Student
类的属性中的 Teacher引用
,所以修改为 tid
即可。
Teacher类
/**
* 教师ID
*/
private int id;
/**
* 教师姓名
*/
private String name;
/**
* 学生集合
*/
private List<Student> studentList;
Student类
/**
* 学生ID
*/
private int id;
/**
* 学生姓名
*/
private String name;
/**
* 关联教师ID
*/
private int tid;
先看看直接查询出来是什么结果,再分析该如何处理。
TeacherMapper
/**
* 通过ID查询教师
* @param id 教师ID
* @return 教师
*/
Teacher getTeacherById(int id);
TeacherMapper.xml
<select id="getTeacherById" resultType="teacher">
select * from mybatis.teacher where id = #{id}
</select>
@Test
public void testGetTeacherById(){
// 获取SqlSession实例
SqlSession sqlSession = MyBatisUtils.getSqlSession();
// 获取Mapper
TeacherMapper mapper = sqlSession.getMapper(TeacherMapper.class);
// 执行方法
Teacher teacher = mapper.getTeacherById(1);
System.out.println(teacher);
// 关闭连接
sqlSession.close();
}
查询结果:学生列表为空。
原因:
teacher表
中没有关于student的字段,无法映射,所以需要通过Mapper配置结果集映射;一对多
的关系,即集合(collection)关系。站在教师的角度,教师对学生是一对多的集合关系。
有以下两种方法:
TeacherMapper.xml
<select id="getTeacherById1" resultMap="teacherMap1">
select id, name
from mybatis.teacher
where id = #{id}
</select>
<resultMap id="teacherMap1" type="teacher">
<!-- column代表传递给子查询的值 -->
<collection property="studentList" column="id" javaType="List" ofType="student" select="listStudentsByTid"/>
</resultMap>
<select id="listStudentsByTid" resultType="student">
select *
from mybatis.student
where tid = #{id}
</select>
分析:
原本的select标签
中的resultType
已无法满足需求,所以应该用resultMap
结果映射。
创建一个resultMap
,用于处理数据库和实体类的映射关系:
result
标签:处理简单映射,若数据库字段和实体类属性能自动映射,无需显式配置;
collection
标签:处理复杂映射,代表多对一的关联关系;
property
:实体类的属性名;
column
:传递给子查询的参数
思路:这里本应该填写数据库表中的有关学生的字段,但是teacher表中没有相应字段,所以先空着。写到后面发现,没有地方给子查询语句传参,所以此处填写的值就是给子查询语句传递参数的。
javaType
:属性的Java类型,使用全限类名或别名;
select
:引用子查询语句,Teacher需要通过学生表的tid查出;
TeacherMapper
<select id="getTeacherById" resultMap="teacherMap">
select t.id as t_id,
t.name as t_name,
s.id as s_id,
s.name as s_name
from mybatis.teacher as t
left join mybatis.student s
on t.id = s.tid
where t.id = #{id}
</select>
<resultMap id="teacherMap" type="teacher">
<result property="id" column="t_id"/>
<result property="name" column="t_name"/>
<collection property="studentList" javaType="ArrayList" ofType="student">
<result property="id" column="s_id"/>
<result property="name" column="s_name"/>
<result property="tid" column="t_id"/>
</collection>
</resultMap>
分析:
原本的select标签
中的resultType
已无法满足需求,所以应该用resultMap
结果映射;
创建一个resultMap
,用于处理数据库和实体类的映射关系:
resultMap
中配置。result
标签:处理简单映射,由于SQL语句中起了别名,所以需要显式配置;
property
:实体类的属性名;column
:数据库表的字段名。collection
标签:处理复杂映射,代表多对一的关联关系;
property
:实体类的属性名;javaType
:属性的Java类型,使用全限类名或别名;ofType
:映射到List集合中指定的泛型类型,使用全限类名或别名;column
和select
两个属性,但需要在内部配置result标签
,将查到的student的字段
映射到Student类的属性
上。相当于以下SQL语句
select t.id as t_id,
t.name as t_name,
s.id as s_id,
s.name as s_name
from teacher as t
left join student s
on t.id = s.tid
where t.id = ?
建议:使用联表查询!
子查询:
属于Student本身的属性
(id、name),跟Teacher有关的属性
(逻辑外键tid);tid
和teacher
;联表查询:
属于Teacher本身的属性
(id、name),并通过联表查询查出Student的属性
(name);原文:https://www.cnblogs.com/secretmrj/p/15070392.html