Mybatis一对多,多对一关系实现
在这里我们来一个小插曲:
给大家介绍一款插件叫Lombok插件
这个插件他的作用就是可以直接一个@Data标签取代Get,Set,ToString,有参和无参构造。
我们安装上之后,就需要我们引入maven依赖
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.10</version>
</dependency>
写入maven依赖以后我们就开始正题.
我们学完了mybatis的动态sql,那他查询的时候只是对单表进行的查询,那我们要是对多表进行一个查询,那我们该怎末写呢??
这里就用到了Mybatis当中的关联关系,首先就是一对多关联关系,再就是多对一关联关系。
那什么是一对多关联关系呢?在这里就举个例子,就拿老师和学生来说,一对多的关联关系就是,一个老师对应多个学生,那相反,多对一的关联关系就是多名学生对应一个老师。
下面我们就用老师学生这个例子具体实现:
首先我们需要创建实体类,需要老师和学生两个,那就需要写两个实体类,同时我们也建立两个表,一个表是student一个表是teacher
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', '1');
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('2', '小南方2', '1');
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('3', '小南方3', '1');
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('4', '小南方4', '1');
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('5', '小南方5', '1');
以上是建立表的sql语句,这里要注意,我们在数据库中新建查询执行命令的时候,我们命令要一段一段(一段一段的意思就是先建表,在插入信息)的执行,如果不一段一段执行,那么就会报错,因为在数据库中可能就会因为插入语句的执行速度会比建表语句的执行速度快,从而找不到表而出现插入错误。好了数据库中的表就创建好了,那我们就开始写实体类:
1).Student.java
package com.nf.domain;
import lombok.Data;
@Data//取代GET,SET,ToString,有参,无参构造
public class Student {
private int id;
private String name;
}
2).Teacher.java
package com.nf.domain;
import lombok.Data;
@Data //取代GET,SET,ToString,有参,无参构造
public class Teacher {
private int id;
private String name;
}
写好两个实体类之后我们开始写接口,不管两个接口有没有用我们都写上,形成一个好习惯。
3).TeacherMapper.java
package com.nf.mapper;
public interface StudentMapper {
}
4).StudentMapper.java
package com.nf.mapper;
public interface TeacherMapper {
}
写好了接口那接下来就需要编写接口所需要的xml文件。
5).TeacherMapper.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="com.nf.mapper.StudentMapper">
</mapper>
6).StudentMapper.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="com.nf.mapper.TeacherMapper">
</mapper>
那到这里我们环境就搭配好了,接下来就开始写例子,我们先写多对一的例子,也就是多名学生对应一个老师的例子。那如何写呢,多名学生对应一个老师,就是先查这多名学生,查出以后在查这多名学生对应的老师分别是谁。
好,那想法有了就开始写。
首先我们需要在实体类Student.java中加入一个属性,因为多名学生它对应的是一个老师,所以我们将老师丢进去,这样每个学生就有一个对象,这个对象就是老师。
Student.java
//多个学生可以是同一个老师,即多对一
private Teacher teacher;
写好了实体类Student那我们就需要写接口查询所有学生的信息,以及相关老师信息
因为我们查询的是所有的学生的信息,所以我们就需要在StudentMappper.java中进行接口编写
StudentMappper.java
//查询所有学生的信息,以及对应的老师的信息
public List<Student> getStudent();
那我们写完了接口就需要写接口对应的xml文件
StudentMappper.xml
我们先进行按照查询进行嵌套处理在进行查询,那什么是按照查询嵌套,下面我们就一边写一边说。
我们先查所有的学生,再根据查询出来的学生的tid,在寻找对应的老师信息
这里我们就用到了resultMap,我们先用select标签查询所有的学生,再用resultMap嵌套处理老师的信息,学生的信息就可以简单的用一个result标签,碰到我们在student.java中定义的Teacher这种复杂的我们就要用association还有collection这两个标签,那这两个标签该怎末用呢?首先是association标签,如果我们的属性是对象的时候就要用association,那如果是集合的话就要用collection.
那在以下association标签中property属性就是我们的student实体类中的复杂属性teacher,column字段名就是tacher对应的id,所以我们就先起名叫tid,再就是我们还需要给他一个teacher类型这里我们用到了javatype属性,那写完了老师这个对象,我们就该查老师当中存在的信息,我们就根据学生表中老师的id查,查完了老师将查询老师的id,也就是getTeacher放入association中的select属性中,那到这里我们的xml文件就写完了
<select id="getStudent" resultMap="Student|Teacher">
select * from student
</select>
<resultMap id="Student|Teacher" type="com.nf.domain.Student">
<!--简单属性直接用result标签-->
<result property="id" column="id"></result>
<result property="name" column="name"></result>
<!--复杂属性我们用单独处理,对象用:association,property属性就是teacher,需要的是teacher中的id字段,还需要给他一个类型就用Java type,teacher类型 集合用:collection-->
<association property="teacher" column="tid" javaType="com.nf.domain.Teacher" select="getTeacher" ></association>
</resultMap>
<select id="getTeacher" resultType="com.nf.domain.Teacher">
select * from teacher where id = #{id}
</select>
那写完了接口所对应的xml文件,开始测试:
@Test
public void getStudent(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
List<Student> studentList = mapper.getStudent();
if(studentList != null){
System.out.println(studentList);
}else {
System.out.println("无用户信息");
}
//释放资源
sqlSession.close();
}
测试结果就是
那接下我们开始用第二种方式,就是按结果进行查询,其实性质跟第一个一样都是用到了reultMap,不同就是第一个sql语句简单,第二个sql语句难一些。
那首先我们先写接口,其实跟上面的一样,我们加一个数字1换一个名字就行。
StudentMapper.java
public List<Student> getStudent1();
在写接口对应的xml文件,这里呢我们就直接将老师的id用sql语句的方式进行查询,老师名字直接用result标签放入association标签中进行查询。
StudentMapper.xml
<!--第二种方法进行按照结果进行嵌套处理-->
<select id="getStudent1" resultMap="Student||Teacher">
select s.id sid,s.name sname,t.name tname
from student s,teacher t
where s.tid = t.id;
</select>
<resultMap id="Student||Teacher" type="com.nf.domain.Student">
<result property="id" column="sid"></result>
<result property="name" column="sname"></result>
<association property="teacher" javaType="com.nf.domain.Teacher">
<result property="name" column="tanme"></result>
</association>
</resultMap>
那写好了xml文件,我们就开始测试
@Test
public void getStudent1(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
List<Student> studentList = mapper.getStudent1();
if(studentList != null){
System.out.println(studentList);
}else {
System.out.println("无用户信息");
}
//释放资源
sqlSession.close();
}
测试结果:
那到这里呢mybatis的多对一关联关系就说完了,一对多的关联关系在Mybatis一对多,多对一关系实现(2)中。其中还有懒加载和分布查询。(以上都是个人笔记,如有错误欢迎指正!!谢谢)