对于多表查询的看法
今日刚学习多表查询,学习完之后自己的看法:
对于一个MyBatis的初学者来说,我对于多表查询来看,其实就是一次性查询多张表。并且这些表有着很大的联系。
1)对于多表查询:就是Collection和Association标签的应用!
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, '秦老师');
-- 创建一个学生表
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');
MyBatis框架的搭建
pom文件:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com</groupId>
<artifactId>mybatis-06</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<dependencies>
<!-- mysql的驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<!-- junit测试 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<!--mybatis依赖-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.2</version>
</dependency>
<!-- 这个就是简化实体类书写的Lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.10</version>
</dependency>
</dependencies>
<build>
<resources>
<resource>
<directory>src/main/java</directory><!--所在的目录-->
<includes>
<!--包括目录下的.properties,.xml 文件都会扫描到-->
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
<resource>
<directory>src/main/resources</directory><!--所在的目录-->
<includes>
<!--包括目录下的.properties,.xml 文件都会扫描到-->
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
</build>
</project>
核心配置文件(记得加上自己的数据库配置文件):
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!-- 引入外部的资源配置文件 -->
<properties resource="db.properties"/>
<!-- 设置日志工厂为Log4j -->
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
<!-- 给sql语句返回的类型起别名 -->
<typeAliases >
<typeAlias type="com.pojo.Teacher" alias="Teacher"/>
<typeAlias type="com.pojo.Student" alias="Student"/>
</typeAliases>
<!-- 进行核心配置文件的环境配置 -->
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
<!--引入接口注解配置-->
<mappers>
<mapper class="com.Dao.TeacherMapper"/>
<mapper class="com.Dao.StudentMapper"/>
</mappers>
</configuration>
编写代码
实体类的编写:根据自己所搭建的数据库来编写!
接口的编写:对应实体类的接口的编写
.xml文件:接口对应的.xml文件的编写
其中关键的问题是.xml文件的编写:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.Dao.StudentMapper">
<!-- 按照结果集查询 -->
<select id="getStudent2" resultMap="StudentTeacher2">
select s.id sid,s.name sname,t.name tname
from student s,teacher t
where s.tid =t.id
</select>
<!-- 使用结果集对象resultMap,直接完成多对一查询 -->
<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>
<!-- 思路:
1.查询所有的学生信息
2.根据查询出来的学生的tid,寻找对应的老师! 子查询
-->
<!-- 对于CRUD标签中的resultType属性来说,
1)如果没有在核心配置文件mybatis-config.xml中,配置起别名设置(typeAliases)
那么对于此时的resultType属性来说,所写的值是————:com.pogo.Student
2)如果在核心配置文件中,配置了别名的设置(typeAliases)
那么对于此时的resultType属性来说,所写的是————:在配置时,所起的别名。
-->
<select id="getStudent" resultMap="StudentTeacher">
select * from student
</select>
<resultMap id="StudentTeacher" type="Student">
<!-- 复杂的属性,我们需要单独处理。
对象:association
集合:collection
-->
<association property="teacher" column="tid" javaType="Teacher" select="getTeacher"/>
</resultMap>
<select id="getTeacher" resultType="Teacher">
select * from teacher where id = #{id}
</select>
</mapper>
测试类的编写
测试类的编写总是千篇一律,但是我对其的书写,还是爱如初恋!
package com.Dao;
import com.pojo.Student;
import com.pojo.Teacher;
import com.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import java.util.List;
public class MyTest {
/**
* 测试查询老师的信息,并且测试整体的MyBatis框架是否搭建成功。
*/
@Test
public void getTeacherMapper(){
//通过创建的工具类,来获取sqlSession对象。其中的sqlSession对象是由核心配置文件,创建sqlSessionFactory工厂,在解析流文件,之后创建sqlSession对象
SqlSession sqlSession = MybatisUtils.getSession();
//通过sqlSession对象获取,TeacherMapper接口中的方法,从而获取mapper对象
TeacherMapper mapper = sqlSession.getMapper(TeacherMapper.class);
//调用接口中的方法,进行测试
Teacher teacher = mapper.getTeacher(1);
//处理结果
System.out.println(teacher);
//关闭资源
sqlSession.close();
}
/**
* 使用子查询:
* 相当于:sql=select sid,sname,teacher from student where id=(select tid from teacher)
* 测试查询学生表,运用在MyBatis框架中的sql语句查询出student和teacher表中联系,实现多对一的查询。
*/
@Test
public void getStudentTest(){
//通过创建的工具类,来获取sqlSession对象。其中的sqlSession对象是由核心配置文件,创建sqlSessionFactory工厂,在解析流文件,之后创建sqlSession对象
SqlSession sqlSession = MybatisUtils.getSession();
//通过sqlSession对象获取,TeacherMapper接口中的方法,从而获取mapper对象
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
//调用接口中的方法,进行测试
List<Student> students = mapper.getStudent();
//处理结果
for (Student student : students) {
System.out.println(student);
}
//关闭资源
sqlSession.close();
}
/**
* 使用结果集查询:
* 测试查询学生表,运用在MyBatis框架中的sql语句查询出student和teacher表中联系,实现多对一的查询。
*/
@Test
public void getStudentTest2(){
//通过创建的工具类,来获取sqlSession对象。其中的sqlSession对象是由核心配置文件,创建sqlSessionFactory工厂,在解析流文件,之后创建sqlSession对象
SqlSession sqlSession = MybatisUtils.getSession();
//通过sqlSession对象获取,TeacherMapper接口中的方法,从而获取mapper对象
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
//调用接口中的方法,进行测试
List<Student> students = mapper.getStudent2();
//处理结果
for (Student student : students) {
System.out.println(student);
}
//关闭资源
sqlSession.close();
}
}
做到这些,那么相信你对于使用MyBatis来处理多表查询,有着一定的了解了!
那么下面让我们做些练习,来巩固一下吧!
对于每个步骤,书写成自己脑海中的语言
把每一步的代码,都加上自己的注释
把每一行代码都敲一遍
处理一对多问题
处理一对多的问题,其实和多对一差不多。这里是一种集合的关系。
举例:一个老师,多个学生。
搭建必要环境同上
编写代码
实体类的编写:根据自己所搭建的数据库来编写!
接口的编写:对应实体类的接口的编写
.xml文件:接口对应的.xml文件的编写
其中,实体类的编写和**.xml文件有着变化**。
实体类的编写
教师表的编写
package com.pojo;
import lombok.Data;
import java.util.List;
//使用Lombok中的注解来完成实体类的写法
@Data
public class Teacher {
private int id;
private String name;
//一个老师有很多个学生,这些学生可以放到一个集合中。可以使用复杂标签Collection来完成一对多的关系。
private List<Student> students;
}
学生表的编写
package com.pojo;
import lombok.Data;
//使用Lombok中的注解来完成实体类的写法
@Data
public class Student {
private int id;
private String name;
private int tid;
public static void main(String[] args) {
System.out.println();
}
}
.xml文件的编写
<?xml version="1.0" encoding="UTF-8" ?>
<!--TeacherMapper.xml文件是位了绑定到TeacherMapper接口。就像JDBC中的sql语句的编写的过程。即便是使用注解开发,但是与接口相对应的.xml文件不可或缺 -->
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--其中mapper的标签的作用:
在核心配置文件中:是为了绑定接口信息
在接口对应的.xml文件中:是为了绑定接口,从而书写对应的sql语句(使用注解开发另说)
-->
<mapper namespace="com.Dao.TeacherMapper">
<!--
思路:
1. 从学生表和老师表中查出学生id,学生姓名,老师姓名
2. 对查询出来的操作做结果集映射
1. 集合的话,使用collection!
JavaType和ofType都是用来指定对象类型的
JavaType是用来指定pojo中属性的类型
ofType指定的是映射到list集合属性中pojo的类型。
-->
<select id="getTeacher" resultMap="TeacherStudent">
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=#{id}
</select>
<resultMap id="TeacherStudent" type="Teacher">
<result property="name" column="tname"/>
<collection property="students" ofType="Student">
<result property="id" column="sid" />
<result property="name" column="sname" />
<result property="tid" column="tid" />
</collection>
</resultMap>
</mapper>
测试类的编写
package com.Dao;
import com.pojo.Teacher;
import com.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import java.util.List;
public class MyTest {
// @Test
// public void getTeacherTest(){
// //首先通过工具类,获取sqlSession对象
// SqlSession sqlSession = MybatisUtils.getSession();
// //再通过sqlSession对象,获取其中的TeacherMapper接口
// TeacherMapper mapper = sqlSession.getMapper(TeacherMapper.class);
// //通过mapper对象,调用接口中的方法
// List<Teacher> teacher = mapper.getTeacher();
// for (Teacher teacher1 : teacher) {
// System.out.println(teacher1);
// }
// //关闭sqlSession对象资源
// sqlSession.close();
// }
@Test
public void getTeacherTest2(){
SqlSession session = MybatisUtils.getSession();
TeacherMapper mapper = session.getMapper(TeacherMapper.class);
Teacher teacher = mapper.getTeacher(1);
System.out.println(teacher);
session.close();
}
}
做到这些,那么相信你对于使用MyBatis来处理多表查询,有着一定的了解了!
那么下面让我们做些练习,来巩固一下吧!
对于每个步骤,书写成自己脑海中的语言
把每一步的代码,都加上自己的注释
把每一行代码都敲一遍
每时每刻的都在进步的你,还怕有什么解决不了的那?
加油!每一个努力的程序猿!