目录
1、多对一处理
1.1、打个比方
比如:多个学生对应一个老师
- 对于学生,
关联
,多个学生关联一个老师【多对一】 - 对于老师,
集合
,一个老师有多个学生【一对多】
1.2、实例环境搭建
- 搭建数据库表
CREATE TABLE `teacher` (
`id` INT(10) NOT NULL,
`name` VARCHAR(30) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8
INSERT INTO teacher(`id`, `name`) VALUES (1, '秦老师');
CREATE TABLE `student` (
`id` INT(10) NOT NULL,
`name` VARCHAR(30) DEFAULT NULL,
`tid` INT(10) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `fktid` (`tid`),
CONSTRAINT `fktid` FOREIGN KEY (`tid`) REFERENCES `teacher` (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('1', '小明', '1');
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('2', '小红', '1');
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('3', '小张', '1');
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('4', '小李', '1');
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('5', '小王', '1');
我们画出两个表对应的关系,从学生这边看,是多对一的关系,student表的tid是外键,对应teacher表的id
- 导入lombok依赖,下载lombok插件
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
<scope>provided</scope>
</dependency>
-
新建实体类Student和Teacher
学生的第三个字段tid对应一个老师,所以学生的实体类Student中第三个属性为Teacher类型
package pojo;
@data
@AllArgsConstructor
@NoArgsConstructor
public class Student {
private int id;
private String name;
//每个学生需要关联一个老师
private Teacher teacher;
}
package pojo;
@data
@AllArgsConstructor
@NoArgsConstructor
public class Teacher {
private int id;
private String name;
}
- 创建StudentMapper和TeacherMapper接口
package mapper;
public interface StudentMapper {
}
package mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import pojo.Teacher;
public interface TeacherMapper {
}
- 创建StudentMapper.xml和Teacher.xml文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="mapper.StudentMapper">
</mapper>
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="mapper.TeacherMapper">
</mapper>
- MyBatis核心配置文件中绑定Mapper接口
<mappers>
<mapper class="mapper.TeacherMapper"/>
<mapper class="mapper.StudentMapper"/>
</mappers>
- 编写测试类
public class MyTest {
}
1.3、目标:查询所有的学生信息以及对应的老师信息
方式一:查询嵌套
在StudentMapper接口中添加getStudent方法,用来查询所有学生
public List<Student> getStudent();
StudentMapper.xml进行配置
- 首先用 getStudent方法 查询所有的学生信息
- 再利用resultMap进行查询嵌套映射
Student实体类
中的id属性 ==>数据库student表
中的id字段Student实体类
中的name属性 ==>数据库student表
中的name字段Student实体类
中的teacher属性 ==>数据库student表
中的tid字段- 利用select标签实现嵌套查询,绑定id为
getStudent
的查询语句,根据查询出来的学生的tid,寻找对应的老师!
- 利用select标签实现嵌套查询,绑定id为
<!--查询嵌套映射-->
<resultMap id="studentTeacher" type="pojo.Student">
<result column="id" property="id"/>
<result column="name" property="name"/>
<!--复杂的属性,我们需要单独处理 对象:association 集合:coLLection-->
<association column="tid" property="teacher" javaType="pojo.Teacher" select="getTeacher"/>
</resultMap>
<select id="getStudent" resultMap="studentTeacher">
select * from student
</select>
<select id="getTeacher" resultType="pojo.Teacher">
select * from teacher where id = #{id}
</select>
测试类中添加测试方法
@Test
public void getStudent() {
SqlSession sqlSession = MyBatisUtils.getSqlSession();
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
List<Student> students = mapper.getStudent();
for (Student student : students) {
System.out.println(student);
}
sqlSession.close();
}
方式二:结果嵌套
StudentMapper.xml进行配置
- 首先用 getStudent2方法 条件查询
- 查询学生的id,别名
sid
- 查询学生的name,别名
sname
- 查询老师的name,别名
tname
- 条件为 学生的tid=老师的id
- 查询学生的id,别名
- 利用resultMap进行结果嵌套映射
Student实体类
中的id属性(sid) ==>数据库student表
中的id字段Student实体类
中的name属性(sname) ==>数据student库表
中的name字段Student实体类
中的teacher属性嵌套映射,由于是一个Teacher对象,使用association标签,且利用javaType指定java类型为Teacher- 对该Teacher对象再次进行映射
Teacher实体类
中的name属性(tname) ==>数据库teacher表
中的name字段
- 对该Teacher对象再次进行映射
<select id="getStudent2" resultMap="studentTeacher2">
select s.id sid,s.name sname,t.name tname
from student s,teacher t
where s.tid=t.id
</select>
<resultMap id="studentTeacher2" type="pojo.Student">
<result column="sid" property="id"/>
<result column="sname" property="name"/>
<association property="teacher" javaType="pojo.Teacher">
<result column="tname" property="name"/>
</association>
</resultMap>
测试类中添加测试方法
@Test
public void getStudent() {
SqlSession sqlSession = MyBatisUtils.getSqlSession();
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
List<Student> students = mapper.getStudent();
for (Student student : students) {
System.out.println(student);
}
sqlSession.close();
}
2、一对多处理
对于老师,集合
,一个老师有多个学生【一对多】
同上搭建环境,不同之处:
实体类
- 老师的第二个字段id对应多个学生,所以老师的实体类Teacher中第二个属性为Student的集合
package pojo;
@data
@AllArgsConstructor
@NoArgsConstructor
public class Student {
private int id;
private String name;
private int tid;
}
package pojo;
@data
@AllArgsConstructor
@NoArgsConstructor
public class Teacher {
private int id;
private String name;
//一个老师有多个学生
private List<Student> students;
}
2.1、目标:获取指定老师下的所有学生及老师的信息
方式一:结果嵌套
在TeacherMapper接口中添加getTeacher方法,用来获取指定老师下的所有学生及老师的信息
//获取指定老师下的所有学生及老师的信息
Teacher getTeacher(@Param("tid") int id);
TeacherMapper.xml进行配置
- 首先用 getTeacer方法 根据指定的老师id条件查询
- 查询学生的id,别名
sid
- 查询学生的name,别名
sname
- 查询老师的name,别名
tname
- 查询老师的id,别名
tid
- 条件为 学生的tid=老师的id
- 查询学生的id,别名
- 利用resultMap进行结果嵌套映射
Teacher实体类
中的id属性(tid) ==>数据库teacher表
中的id字段Teacher实体类
中的name属性(tname) ==>数据库teacher表
中的name字段Teacher实体类
中的student集合属性嵌套映射,由于是Student集合,所以使用collection标签,并且利用oftype指定集合的泛型类型- 对该Student集合再进行映射
Student实体类
中的id属性(sid) ==>数据库student表
中的id字段Student实体类
中的name属性(sname) ==>数据student库表
中的name字段Student实体类
中的tid属性 ==>数据student库表
中的tid字段
- 对该Student集合再进行映射
<!--结果嵌套映射-->
<select id="getTeacher" resultMap="teacherStudent">
select s.id sid,s.name sname,t.name tname,t.id tid
from student s,teacher t
where s.tid=t.id and t.id=#{tid}
</select>
<resultMap id="teacherStudent" type="pojo.Teacher">
<result column="tid" property="id"/>
<result column="tname" property="name"/>
<!--
javaType:指定属性的类型
集合中的泛型信息,用oftype获取
-->
<collection property="students" ofType="pojo.Student">
<result column="sid" property="id"/>
<result column="sname" property="name"/>
<result column="tid" property="tid"/>
</collection>
</resultMap>
测试类中添加测试方法
@Test
public void getStudent() {
SqlSession sqlSession = MyBatisUtils.getSqlSession();
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
List<Student> students = mapper.getStudent();
for (Student student : students) {
System.out.println(student);
}
sqlSession.close();
}
得到结果
方式二:查询嵌套
TeacherMapper.xml进行配置
- 首先用 getTeacher2方法 查询所有的老师信息
- 利用resultMap进行查询嵌套映射
Teacher实体类
中的id属性 ==>数据库teacher表
中的id字段Teacher实体类
中的name属性 ==>数据库teacher表
中的name字段Teacher实体类
中的student集合属性 ==>数据库teacher表
中的id字段- 利用select标签实现嵌套查询,绑定id为
getStudentByTeacherID
的查询语句,根据查询出来的老师的id,寻找对应的学生!
- 利用select标签实现嵌套查询,绑定id为
<select id="getTeacher2" resultMap="teacherStudent2">
select * from teacher
</select>
<!--结果映射-->
<resultMap id="teacherStudent2" type="pojo.Teacher">
<collection property="students" javaType="ArrayList" ofType="Student"
select="getStudentByTeacherID" column="id"/>
</resultMap>
<select id="getStudentByTeacherID" resultType="pojo.Student">
select * from student where tid=#{tid};
</select>
测试类中添加测试方法
@Test
public void getTeacher2() {
SqlSession sqlSession = MyBatisUtils.getSqlSession();
TeacherMapper mapper = sqlSession.getMapper(TeacherMapper.class);
Teacher teacher2 = mapper.getTeacher2(1);
System.out.println(teacher2);
sqlSession.close();
}
3、小结
- 关联
association
【多对一】 - 集合
collection
【一对多】 - javaType 和 ofType
- javaType用来指定实体类中属性的类型
- ofType用来指定映射到集合中的pojo类型,泛型的约束类型
4、注意点
- 保证SQL的可读性,尽量保证通俗易懂
- 注意一对多和多对一中,属性和字段的问题
- 问题不好排查的情况下,建议使用日志排错