mybatis一对一关联关系

  这篇文章介绍mybatis如何处理一对一的关联关系,假设现在有班级类(表)和教师类(表),一个教师对应一个班级,一个班级也只对应一个教师。
  
首先创建表并插入数据:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
CREATE TABLE teacher(
t_id INT PRIMARY KEY AUTO_INCREMENT,
t_name VARCHAR(20)
);
CREATE TABLE class(
c_id INT PRIMARY KEY AUTO_INCREMENT,
c_name VARCHAR(20),
teacher_id INT
);
ALTER TABLE class ADD CONSTRAINT fk_teacher_id FOREIGN KEY (teacher_id) REFERENCES teacher(t_id);
INSERT INTO teacher(t_name) VALUES('LS1');
INSERT INTO teacher(t_name) VALUES('LS2');
INSERT INTO class(c_name, teacher_id) VALUES('bj_a', 1);
INSERT INTO class(c_name, teacher_id) VALUES('bj_b', 2);

image_1b4d0n484ohg1bg8m701pkegv59.png-15.1kB

image_1b4d0ndqt1d001otb3bd1kbo6tfm.png-15.2kB

其中,class表中的teacher_id是指向teacher表的外键:
image_1b4d0sebt4d3e9r1fhjgm7e813.png-17.9kB

创建实体类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class Teacher {
private int id;
private String name;
@Override
public String toString() {
return "Teacher [id=" + id + ", name=" + name + "]";
}
public Teacher(int id, String name) {
super();
this.id = id;
this.name = name;
}
public Teacher() {
super();
}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class Classes {
private int id;
private String name;
private Teacher teacher;
@Override
public String toString() {
return "Classes [id=" + id + ", name=" + name + ", teacher=" + teacher + "]";
}
public Classes(int id, String name, Teacher teacher) {
super();
this.id = id;
this.name = name;
this.teacher = teacher;
}
public Classes() {
super();
}
}

主要的处理过程在Classes类的映射文件classesMapper.xml中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.mybatis.test5.classesMapper">
<!--
根据班级id查询班级信息(带老师的信息)
##1. 联表查询
SELECT * FROM class c,teacher t WHERE c.teacher_id=t.t_id AND c.c_id=1;
##2. 执行两次查询
SELECT * FROM class WHERE c_id=1; //teacher_id=1
SELECT * FROM teacher WHERE t_id=1;//使用上面得到的teacher_id
-->
<!--
方式一:嵌套结果:使用嵌套结果映射来处理重复的联合结果的子集
封装联表查询的数据(去除重复的数据)
select * from class c, teacher t where c.teacher_id=t.t_id and c.c_id=1
-->
<select id="getClassesById" parameterType="int" resultMap="classesResultMap">
select * from class c,teacher t where c.teacher_id=t.t_id and
c.c_id=#{id}
</select>
<resultMap type="Classes" id="classesResultMap">
<id property="id" column="c_id"/>
<result property="name" column="c_name"/>
<association property="teacher" javaType="Teacher">
<id property="id" column="t_id"/>
<result property="name" column="t_name"/>
</association>
</resultMap>
<!--
方式二:嵌套查询:通过执行另外一个SQL映射语句来返回预期的复杂类型
SELECT * FROM class WHERE c_id=1;
SELECT * FROM teacher WHERE t_id=1 //1 是上一个查询得到的teacher_id的值
-->
<!--
查询所有的班级信息,包括教师信息
-->
<select id="getAllClasses" resultMap="allClassesResultMap">
select * from class
</select>
<resultMap type="Classes" id="allClassesResultMap">
<id property="id" column="c_id"/>
<result property="name" column="c_name"/>
<association property="teacher" column="teacher_id" select="getTeacherById">
</association>
</resultMap>
<select id="getTeacherById" parameterType="int" resultType="Teacher">
select t_name name from teacher where t_id=#{id}
</select>
</mapper>

这里介绍了两种方法,第一种是通过联表查询,获取每条class记录执行一次select语句:

1
SELECT * FROM class c,teacher t WHERE c.teacher_id=t.t_id AND c.c_id=?;

另一种方法是通过两次查询,先查找class,再根据查找到的class的teacher_id查询teacher,即获取每条class记录执行两次select语句:

1
2
SELECT * FROM class WHERE c_id=?;
SELECT * FROM teacher WHERE t_id=?;

其中的一个重点是resultMap节点中的association节点,它将查询到的列值赋给Classes类的Teacher属性类的对应字段。另外,在第二种方法中,association节点的select属性指定了第二次查询的select节点。
association节点的属性如下:

  • property:对象属性的名称
  • javaType:对象属性的类型
  • column:对应的外键字段名称
  • select:使用的另一个查询的id