复杂查询CRUD.
目录结构
多对一(假设多个学生被一个老师教).
一个Student实体里面有一个Teacher类型属性,学生与老师对应关系是多对一
测试环境搭建.
(已配置好mybatis-config.xml配置文件,写好MybatisUtils.java工具类)
1.导入lombok.
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, '老师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','1'),
('2','学生2','1'),
('3','学生3','1'),
('4','学生4','1'),
('5','学生5','1');
3.新建实体类(重点).
@Data
public class Student {
private int id;
private String name;
private Teacher teacher; // 一个学生实例 里面有 一个老师
}
@Data
public class Teacher {
int id;
String name;
}
4.新建Mapper接口.
public interface StudentMapper {
}
public interface TeacherMapper {
}
5.建立Mapper.xml文件.
<?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="dao.TeacherMapper">
</mapper>
<?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="dao.StudentMapper">
</mapper>
6.绑定Mapper到mybatis-config.xml
.
<mappers>
<mapper resource="dao/StudentMapper.xml"/>
<mapper resource="dao/TeacherMapper.xml"/>
</mappers>
按照查询嵌套处理.
- 创建两个查询语句,一个查询套着另一个查询(通过一个表的外键,查出对应另一个表的内容,然后将这些内容,与前表关联合并)
接口方法
public interface StudentMapper {
//查询所有的学生信息以及对应老师的信息
List<Student> getStudent();
}
StudentMapper.xml
SQL语句编写
<!--
这种方式相当于 子查询
select id,name,tid from mybatis.student ==> tid
-->
<mapper namespace="dao.StudentMapper">
<select id="getStudent" resultMap="StudentTeacher">
select * from mybatis.student;
</select>
<resultMap id="StudentTeacher" type="pojo.Student">
<result property="id" column="id"/>
<result property="name" column="name"/>
<association property="teacher" column="tid" javaType="pojo.Teacher" select="getTeacher"/>
</resultMap>
<select id="getTeacher" resultType="pojo.Teacher">
select * from mybatis.teacher where id=#{tid};
</select>
</mapper>
上面的 association 中的 column : tid 是指①在getStudent中 结果列中 某一个值对应的别名或名字 (tid)②同样也是即将传入getTheacher的 #{对应名字的参数}
无论sql是否在同一个mapper.xml文件中,都可以使用 association 的select属性(需要全限定名)去加载sql,获取其返回结果(多对一:单个结果–对象,一对多:多个结果-List<对象>)
测试
@Test
public void getStudent(){
try(SqlSession sqlSession = MybatisUtils.getSqlSession();) {
StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
List<Student> list = studentMapper.getStudent();
list.forEach(System.out::println);
}
}
结果展示
按照结果嵌套处理.
- 一条查询语句,需要在resultMap中进行处理,对sql编写能力要求高
与查询嵌套处理一致,除了
StudentMapper.xml
文件内容不一样
StudentMapper.xml
编写Sql
<mapper namespace="dao.StudentMapper">
<select id="getStudent" resultMap="StudentTeacher">
select s.id sid,s.name sname,t.id tid, t.name tname
from student s, teacher t
where s.tid = t.id;
</select>
<resultMap id="StudentTeacher" type="pojo.Student">
<result property="id" column="sid"/>
<result property="name" column="sname"/>
<association property="teacher" javaType="pojo.Teacher">
<result property="id" column="tid"/>
<result property="name" column="tname"/>
</association>
</resultMap>
</mapper>
结果展示
一对多(假设一个老师教多个学生).
- 教师表的一条记录对应学生表的多条记录
一个Teacher实体中有一个 List<Student>类型的属性
对于多对多的情况,就需要一个中间实体(包含两个实体的主键)
一个Teacher实体中有一个List<Student>类型的属性
一个Student实体中有一个List<Teacher>类型的属性
一个Teacher_Student实体 包含 Teacher和Student两个实体的主键 作为外键 当然可以把这个两个属性作为联合主键
//实体类
class Teacher{
int id;
int name;
}
class Student{
int id;
int name;
}
class Studnet{
int tid;
int sid;
/*
tid,sid 联合为主键 (tid 不是主键,sid不是主键,两个合起来才叫主键)
tid : 作为外键(Teacher)
(Student)
*/
}
多对多.
就是两个一对多
小结.
两种查询方式比较.
- 嵌套查询的查询语句写起来简单,但是执行的sql语句多,性能要低一点
- 嵌套结果的查询语句写起来难一点,而且sql语句只执行一条,性能相对较高
复杂的属性,我们需要单独处理 – 即除了基本类型.
- 对象:association – 多对一
- 集合:collection – 一对多
javaType 和 ofType.
javaType:指定实体类中属性的类型 但是如果是类型是集合 就使用ofType
ofType:用于指定集合中的泛型的约束类型
一对一.
比如qq账号 和 qq空间
一个账号对应一个空间,一个空间对应一个账号
外键可以在任意一个表上
一对多和多对一.
假设 所有学生只有一个老师教 用班级和学生好
- 多个学生被一个老师教,且每个学生只有一个老师
- 一个老师教多个学生 (一个老师有多个学生)
- 学生依赖于老师,学生表为子表(存在主键和外键),老师表为父表(只有主键)
多对多.
假设 所有学生有多个老师教 其实老师和学生符合多对多
- 一个学生被多个老师教(每个学生有多个老师)
- 一个老师教多个学生(每个老师有多个学生)
- 此时比较复杂,必须要一个中间表