多對一和一對多
多對一
多對一的理解:
-
多個學生對應一個老師
-
如果對于學生這邊,就是一個多對一的現象,即從學生這邊關聯一個老師!
結果映射(resultMap):
-
association
-
- 一個復雜類型的關聯;許多結果將包裝成這種類型
-
- 嵌套結果映射 —— 關聯可以是 resultMap 元素,或是對其它結果映射的引用
-
collection
-
- 一個復雜類型的集合
-
- 嵌套結果映射 —— 集合可以是 resultMap 元素,或是對其它結果映射的引用
以下使用兩種方式實現以下sql語句:
select s.id ,s.name ,t.name from student s,teacher t where s.tid=t.id
1、按照查詢嵌套處理
類似子查詢
- 數據庫設計
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和Teacher
public class Teacher {private int id;private String name;public Teacher(){}public int getId() {return id;}public void setId(int id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}@Overridepublic String toString() {return "Teacher{" +"id=" + id +", name='" + name + '\'' +'}';}
}
public class Student {private int id;public String getName() {return name;}public void setName(String name) {this.name = name;}private String name;private Teacher teacher;//學生需要關聯一個老師public Student(){}public int getId() {return id;}public void setId(int id) {this.id = id;}public Teacher getTeacher() {return teacher;}public void setTeacher(Teacher teacher) {this.teacher = teacher;}@Overridepublic String toString() {return "Student{" +"id=" + id +", name='" + name + '\'' +", teacher=" + teacher +'}';}
}
- StudentMapper接口和TeacherMapper
package com.study.dao;
import com.study.pojo.Student;
import java.util.List;public interface StudentMapper {//查詢所有的學生信息,以及對應的老師的信息public List<Student> getStudent();
}
public interface TeacherMapper {}
- StudentMapper.xml映射文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--namespace綁定一個對應的Dao/Mapper接口的全限定名-->
<mapper namespace="com.study.dao.StudentMapper"><resultMap id="StudentTeacher" type="Student"><!--主鍵可使用<id>--><result property="id" column="id"/><result property="name" column="name"/><!--復雜的屬性,需要單獨處理——引用類型:<association> 集合:<collection>--><association property="teacher" column="tid" javaType="Teacher" select="getTeacher"/></resultMap><select id="getStudent" resultMap="StudentTeacher">select * from student</select><select id="getTeacher" resultType="Teacher">select * from teacher where id=#{id}</select>
</mapper>
- 核心配置文件
<mappers><mapper class="com.study.dao.TeacherMapper"/><mapper class="com.study.dao.StudentMapper"/>
</mappers>
- 測試
@Test
public void testStudent(){SqlSession sqlSession = MybatisUtils.getSqlSession();StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);List<Student> studentList = mapper.getStudent();//動態代理產生一個實現Mapper接口的對象并賦值個,將該對象賦值給接口的引用for (Student student : studentList) {System.out.println(student);}sqlSession.close();
}
2、按結果嵌套處理
-
StudentMapper接口
public List<Student> getStudent2();
-
StudentMapper.xml
<!--===========按照結果嵌套查詢==============--><!--按查詢結果嵌套處理思路:1. 直接查詢出結果,進行結果集的映射--> <select id="getStudent2" resultMap="StudentTeacher2">select s.id sid,s.name sname,t.name tnamefrom student s,teacher twhere s.tid=t.id; </select><resultMap id="StudentTeacher2" type="Student"><result property="id" column="sid"/><result property="name" column="sname"/><association property="teacher" javaType="Teacher" ><result property="name" column="tname"/></association> </resultMap>
-
測試
@Test public void testStudent(){SqlSession sqlSession = MybatisUtils.getSqlSession();StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);List<Student> studentList = mapper.getStudent2();//動態代理產生一個實現Mapper接口的對象并賦值個,將該對象賦值給接口的引用for (Student student : studentList) {System.out.println(student);}sqlSession.close(); }
小結
- 按照查詢進行嵌套處理就像SQL中的子查詢
- 按照結果進行嵌套處理就像SQL中的聯表查詢
一對多
-
實體類
package com.study.pojo;public class Student {private int id;public String getName() {return name;}public void setName(String name) {this.name = name;}private String name;public int getTid() {return tid;}public void setTid(int tid) {this.tid = tid;}private int tid;public Student(){}public int getId() {return id;}public void setId(int id) {this.id = id;}@Overridepublic String toString() {return "Student{" +"id=" + id +", name='" + name + '\'' +", tid=" + tid +'}';} }
package com.study.pojo;import java.util.List;public class Teacher {private int id;private String name;private List<Student> students;//一個老師擁有多個學生public List<Student> getStudents() {return students;}public void setStudents(List<Student> students) {this.students = students;}public Teacher(){}public int getId() {return id;}public void setId(int id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}@Overridepublic String toString() {return "Teacher{" +"id=" + id +", name='" + name + '\'' +", students=" + students +'}';} }
-
TeacherMapper接口
List<Teacher> getTeacher();
-
TeacherMapper.xml
<select id="getTeacher" resultType="Teacher">select * from teacher; </select>
-
核心配置文件中注冊Mapper
-
測試環境正常
@Test public void test(){SqlSession sqlSession = MybatisUtils.getSqlSession();TeacherMapper mapper = sqlSession.getMapper(TeacherMapper.class);List<Teacher> teacherList = mapper.getTeacher();for (Teacher teacher : teacherList) {System.out.println(teacher);}sqlSession.close(); }
1、按結果嵌套查詢
-
TeacherMapper接口`
Teacher getTeacherById(@Param("tid")int id);
-
TeaccherMapper.xml——按結果嵌套查詢
<!--==================按結果嵌套查詢================--> <select id="getTeacherById" resultMap="TeacherStudent">select t.name tname,t.id tid,s.id sid,s.name snamefrom student s,teacher twhere s.tid=t.id and t.id=#{tid} </select><resultMap id="TeacherStudent" type="Teacher"><result property="id" column="tid"/><result property="name" column="tname"/><!--復雜的屬性,需要單獨處理——引用類型:<association> javaType:指定的屬性的類型集合:<collection> 集合中的泛型信息,我們使用ofType獲取--><!--Teacher實體類中有一個名為students的引用類型的List集合,將List中Student對象的各屬性與sql語句返回的字段進行映射--><collection property="students" ofType="Student"><result property="id" column="sid"/><result property="name" column="sname"/><result property="tid" column="tid"/></collection> </resultMap>
-
測試
@Test public void getTeacherById(){SqlSession sqlSession = MybatisUtils.getSqlSession();TeacherMapper mapper = sqlSession.getMapper(TeacherMapper.class);Teacher teacher = mapper.getTeacherById(1);System.out.println(teacher);sqlSession.close(); }輸出: Opening JDBC Connection Created connection 1278254413. ==> Preparing: 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=? ==> Parameters: 1(Integer) <== Columns: sid, sname, tname, tid <== Row: 1, 小明, 秦老師, 1 <== Row: 2, 小紅, 秦老師, 1 <== Row: 3, 小張, 秦老師, 1 <== Row: 4, 小李, 秦老師, 1 <== Row: 5, 小王, 秦老師, 1 <== Total: 5 Teacher{id=1, name='秦老師', students=[Student{id=1, name='小明', tid=1}, Student{id=2, name='小紅', tid=1}, Student{id=3, name='小張', tid=1}, Student{id=4, name='小李', tid=1}, Student{id=5, name='小王', tid=1}]} Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@4c309d4d] Returned connection 1278254413 to pool.
2、按照查詢嵌套處理
-
TeacherMapper
Teacher getTeacherById2(@Param("tid")int id);
-
TeacherMapper.xml
<!--===========按照查詢嵌套處理================--> <select id="getTeacherById2" resultMap="TeacherStudent2">select * from mybatis.teacher where id=#{tid} </select><resultMap id="TeacherStudent2" type="Teacher"><collection property="students" javaType="ArrayList" ofType="Student" select="getStudentByTeacherId" column="id"/><!--這里的column="id"是teacher表中的id--> </resultMap><select id="getStudentByTeacherId" resultType="Student"><!--這里的id是上文中的id-->select * from student where tid=#{id} </select>
-
測試
@Testpublic void getTeacherById2() {SqlSession sqlSession = MybatisUtils.getSqlSession();TeacherMapper mapper = sqlSession.getMapper(TeacherMapper.class);Teacher teacher = mapper.getTeacherById2(1);System.out.println(teacher);sqlSession.close();}輸出: Opening JDBC Connection Created connection 931675031. ==> Preparing: select * from mybatis.teacher where id=? ==> Parameters: 1(Integer) <== Columns: id, name <== Row: 1, 秦老師 ====> Preparing: select * from student where tid=? ====> Parameters: 1(Integer) <==== Columns: id, name, tid <==== Row: 1, 小明, 1 <==== Row: 2, 小紅, 1 <==== Row: 3, 小張, 1 <==== Row: 4, 小李, 1 <==== Row: 5, 小王, 1 <==== Total: 5 <== Total: 1 Teacher{id=0, name='秦老師', students=[Student{id=1, name='小明', tid=1}, Student{id=2, name='小紅', tid=1}, Student{id=3, name='小張', tid=1}, Student{id=4, name='小李', tid=1}, Student{id=5, name='小王', tid=1}]} Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@37883b97] Returned connection 931675031 to pool.
-
小結
-
關聯:association【多對一】
-
集合:collection 【一對多】
-
association是用于一對一和多對一,而collection是用于一對多的關系
-
javaType & ofType
-
- JavaType是用來指定pojo中屬性的類型
-
- ofType指定的是映射到list集合屬性中pojo的類型。
注意說明:
1、保證SQL的可讀性,盡量通俗易懂
2、根據實際要求,盡量編寫性能更高的SQL語句
3、注意屬性名和字段不一致的問題
4、注意一對多和多對一 中:字段和屬性對應的問題
5、盡量使用Log4j,通過日志來查看自己的錯誤
面試高頻:
-
Mysql引擎
-
InnoDB底層原理
-
索引
d=4, name=‘小李’, tid=1}, Student{id=5, name=‘小王’, tid=1}]}
Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@37883b97]
Returned connection 931675031 to pool.
```
小結
-
關聯:association【多對一】
-
集合:collection 【一對多】
-
association是用于一對一和多對一,而collection是用于一對多的關系
-
javaType & ofType
-
- JavaType是用來指定pojo中屬性的類型
-
- ofType指定的是映射到list集合屬性中pojo的類型。
注意說明:
1、保證SQL的可讀性,盡量通俗易懂
2、根據實際要求,盡量編寫性能更高的SQL語句
3、注意屬性名和字段不一致的問題
4、注意一對多和多對一 中:字段和屬性對應的問題
5、盡量使用Log4j,通過日志來查看自己的錯誤
面試高頻:
-
Mysql引擎
-
InnoDB底層原理
-
索引
-
索引優化