mybatis 关联关系
一、三种关系:
- 一对一:一个班主任只属于一个班级,一个班级也只能有一个班主任
- 一对多:一个班级有多个学生,一个学生只属于一个班级
- 多对多:一个学生可以选多门课,一门课可以有多个学生选
二、一对一
一个班主任只属于一个班级,一个班级也只能有一个班主任。
教师表:
create table teacher(
id int primary key auto_increment,
name varchar(20),
age int);
insert into teacher(name,age) values('小明',18);
教室表:
t_id是教师id
create table room(
id int primary key auto_increment,
name varchar(20),
t_id int unique,
foreign key(c_ht_id) references tb_head_teacher(ht_id));
insert into room(name,t_id) values('教室1',1);
实体类:
@Data
public class Teacher{
private Integer id;
private String name;
private Integer age;
}
@Data
public class Classes {
private Integer id;
private String name;
private Teacher teacher;//teacher 属性用来映射一对一的关联关系,表示这个班级的班主任
}
mapper接口和xml
查询教室和班主任
//RoomMapper 接口
public interface RoomMapper {
/*
* 根据 id 查询班级 Room
* @param id
* @return
* @throws Exception
*/
public Room selectRoomById(Integer id) throws Exception;
}
RoomMapper.xml 的配置
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org/DTD Mapper 3.0" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="包名.dao.RoomMapper">
<select id="selectRoomById" parameterType="int" resultMap="classmap">
select * from room r, teacher t where r.t_id = t.id and r.id=#{id}
</select>
<!-- resultMap: 映射实体类和字段之间的一一对应的关系 -->
<resultMap id="roommap" type="包名.entity.Room">
<id property="id" column="id" />
<result property="name" column="name" />
<!-- 一对一关联映射:association -->
<association property="teacher" javaType="包名.entity.Teacher">
<id property="id" column="t_id" />
<result property="name" column="name" />
<result property="age" column="age" />
</association>
</resultMap>
</mapper>
嵌套结果映射
原理:采用的是关联的嵌套结果映射
的方式,使用了 <association.../> 元素
映射一对一的关联关系。
如果想要 Teacher 的结果映射可以重用,我们可以采用下面的方式,先定义 Teacher 的 resultMap:
<resultMap id="teachermap" type="Teacher">
<id property="id" column="id"/>
<result property="name" column="name" />
<result property="age" column="age" />
</resultMap>
<resultMap id="roommap" type="Room">
<id property="id" column="c_id" />
<result property="name" column="c_name" />
<!-- 一对一关联映射:association -->
<association property="teacher" column="t_id" javaType="Teacher" resultMap="teachermap" />
</resultMap>
三、 一对多
一个班级有多个学生(一对多),一个学生只属于一个班级(多对一)
教室表:
create table room(
id int primary key auto_increment,
name varchar(20));
insert into room(name) values('教室1');
学生表:
create table student(
id int primary key auto_increment,
name varchar(20),
sex varchar(10),
age int,
r_id int,
foreign key(r_id) references room(id));
insert into student(name,sex,age,r_id) values('小明', 1,18,1);
insert into student(name,sex,age,r_id) values('小花',0,19,1);
insert into student(name,sex,age,r_id) values('小强',0,18,1);
实体:
@Data
public class Student {
private Integer id;
private String name;
private String sex;
private Integer age;
}
@Data
public class Room {
private Integer id;
private String name;
// 班级和学生是一对多的关系,即一个班级可以有多个学生,这个很关键
private List<Student> students;
}
查询 教室的学生
//RoomMapper 接口的代码如下:
public interface RoomMapper {
/*
* 根据 id 查询班级 Room 和它的学生
* @param id
* @return
* @throws Exception
*/
public Room selectRoomAndStudentsById(Integer id) throws Exception;
}
//RoomMapper.xml 的配置如下:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org/DTD Mapper 3.0" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="包名.dao.RoomMapper">
<select id="selectClassAndStudentsById" parameterType="int" resultMap="roommap">
select r.id,r.name,s.id,s.name,s.sex,s.age from room r left outer
join student s on r.id = s.r_id where r.id=#{id}
</select>
<!-- resultMap: 映射实体类和字段之间的一一对应的关系 -->
<resultMap id="roommap" type="Room">
<id property="id" column="id" />
<result property="name" column="name" />
<!-- 一对多关联映射:collection -->
<collection property="students" ofType="Student">
<id property="id" column="id" />
<result property="name" column="name" />
<result property="sex" column="sex" />
<result property="age" column="age" />
</collection>
</resultMap>
</mapper>
采用的是集合的
嵌套结果映射
的方式,使用了<collection.../> 元素
映射一对多的关联关系。
如果想要 Student 的结果映射可以重用,我们可以定义一个 Student 类型的 resultMap,再在 <collection.../>
中用 resultMap=
引用,同 <association.../>
。
四、 多对多
创建学生表 student 并插入两条数据:
create table student(
id int primary key auto_increment,
name varchar(20),
sex varchar(10),
age int);
insert into student(name,sex,age) values('Tom','male',18);
insert into student(name,sex,age) values('Jack','male',19);
创建课程表 course 并插入两条数据:
create table course(
id int primary key auto_increment,
name varchar(20),
credit int);
insert into course(name,credit) values('Math',5);
insert into course(name,credit) values('Computer',4);
由于学生和课程是多对多的关联关系,因此创建中间表:选课表 select_course 并插入数据
create table select_course(
s_id int,
c_id int,
date date,
primary key(s_id,c_id),
foreign key(s_id) references student(id),
foreign key(c_id) references course(id));
insert into select_course(s_id,c_id,date) values(1,1,'2020-03-01');
insert into select_course(s_id,c_id,date) values(1,2,'2020-03-01');
insert into select_course(s_id,c_id,date) values(2,1,'2020-03-02');
insert into select_course(s_id,c_id,date) values(2,2,'2020-03-02');
实体类: 特别注意需要一个关系类
public class Student {
private Integer id;
private String name;
private String sex;
private Integer age;
private List<Course> courses;
}
public class Course {
private Integer id;
private String name;
private Integer credit;
private List<Student> students;
}
public class StudentCourseLink {
private Student student;
private Course course;
private Date date;
}
接口类
public interface StudentMapper {
/*
* 查询所有学生及他们的选择课程的信息
* @return
* @throws Exception
*/
public List<Student> selectStudentCourse() throws Exception;
/*
* 删除指定 id 用户的某门课(根据课程 id)的选课情况
* @param StudentCourseLink
* @throws Exception
*/
public void deleteStudentCourseById(StudentCourseLink scLink) throws Exception;
}
StudentMapper.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org/DTD Mapper 3.0" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="shiyanlou.mybatis.manytomany.mapper.StudentMapper">
<!-- 查询所有学生及他们的选择课程的信息 -->
<select id="selectStudentCourse" resultMap="studentCourseMap">
select
s.*,c.* from
student s,course c,select_course sc
where s.s_id=sc.s_id
and c.c_id=sc.c_id
</select>
<!-- 根据学生 id 和课程 id 删除该学生该门课的选课情况 -->
<delete id="deleteStudentCourseById" parameterType="StudentCourseLink">
delete from select_course where s_id=#{student.id} and c_id=#{course.id}
</delete>
<!-- resultMap: 映射实体类和字段之间的一一对应的关系 -->
<resultMap id="studentCourseMap" type="Student">
<id property="id" column="id" />
<result property="name" column="name" />
<result property="sex" column="sex" />
<result property="age" column="age" />
<!-- 多对多关联映射:collection -->
<collection property="courses" ofType="Course">
<id property="id" column="id" />
<result property="name" column="name" />
<result property="credit" column="credit" />
</collection>
</resultMap>
</mapper>
List<Student> students = mapper.selectStudentCourse();
Student student = new Student();
student.setId(1);
Course course = new Course();
course.setId(2);
StudentCourseLink scLink = new StudentCourseLink();
scLink.setStudent(student);
scLink.setCourse(course);
mapper.deleteStudentCourseById(scLink);