前言:
小伙伴们,大家好,我是狂奔の蜗牛rz,当然你们可以叫我蜗牛君,我是一个学习Java半年多时间的小菜鸟,同时还有一个伟大的梦想,那就是有朝一日,成为一个优秀的Java架构师。
这个Mybatis基础学习系列是用来记录我学习Mybatis框架基础知识的全过程 (这个系列是参照B站狂神的Mybatis最新教程来写的,由于是之前整理的,但当时没有发布出来,所以有些地方可能有错误,希望大家能够及时指正!)
之后我将尽量以两天一更的速度更新这个系列,还没有学习Mybatis3框架的小伙伴可以参照我的博客学习一下;当然学习过的小伙伴,也可以顺便跟我一起复习一下基础。最后,希望能够和大家一同进步吧!加油吧!少年们!
特别提醒:如果对Mybatis基础学习系列感兴趣,可以阅读本系列往期博客:
第一篇:Mybatis基础学习之初识Mybatis
第二篇:Mybatis基础学习之第一个Mybatis程序
第三篇:Mybatis基础学习之CRUD增删改查
第四篇:Mybatis基础学习之万能的Map和模糊查询
第五篇: Mybatis基础学习之配置解析(上篇)
第六篇: Mybatis基础学习之配置解析(下篇)
第七篇: Mybatis基础学习之使用ResultMap解决字段名不一致
第八篇: Mybatis基础学习之日志工厂的简单使用
第九篇: Mybatis基础学习之数据分页的简单使用
第十篇: Mybatis基础学习之使用注解开发
第十一篇: Mybatis基础学习之Lombok的简单使用
第十二篇: Mybatis基础学习之多对一关系处理
今天我们来到了Mybatis基础学习的第十二站:一对多关系处理。废话不多说,让我们开始今天的学习内容吧。
12.一对多关系处理
- 什么是一对多关系处理?
比如,一个老师拥有多个学生,对于老师而言,这就是一对多的关系!
12.1 搭建基本环境
12.1.1 编写实体类和工具类
1.编写Student实体类
package com.kuang.pojo;
@Data // 引入无参构造、get、set、toString等方法
@AllArgsConstructor // 引入有参构造方法
@NoArgsConstructor // 再次引入无参构造方法, 防止被有参构造覆盖
public class Student {
private int id;
private String name;
private int tid;
}
2.编写Teacher实体类
package com.kuang.pojo;
@Data // 引入无参构造、get、set、toString等方法
@AllArgsConstructor // 引入有参构造方法
@NoArgsConstructor // 再次引入无参构造方法, 防止被有参构造覆盖
public class Teacher {
private int id; // 教师编号
private String name; // 教师姓名
// 一个老师拥有多个学生, 使用泛型为Student的List集合来实现一对多
private List<Student> students;
}
3.编写MybatisUtils工具类
package com.kuang.utils;
/**
* SqlSessionFactoryBuilder(建造工厂)
* --> sqlSessionFactory(生产sqlSession)
* --> sqlSession
*/
public class MybatisUtils {
// 获取静态SQL会话工厂
private static SqlSessionFactory sqlSessionFactory;
// 静态方法体
static {
try {
// 读取配置文件
String resource = "mybatis-config.xml";
// 解析配置文件流
InputStream inputStream = Resources.getResourceAsStream(resource);
// 获取工厂
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* SqlSession 提供了在数据库执行 SQL 命令所需的所有方法
*/
public static SqlSession getSqlSession() {
// 设置参数为true,实现自动提交
return sqlSessionFactory.openSession(true);
}
}
12.1.2 编写Mapper接口及其映射文件
1.编写StudentMapper接口及其映射文件
1-1 编写StudentMapper接口
package com.kuang.dao;
public interface StudentMapper {
}
1-2 编写StudentMapper.xml映射文件
-
在resources文件目录下创建com.kuang.dao包
-
创建并编写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.kuang.dao.StudentMapper">
</mapper>
2.编写TeacherMapper接口及其映射文件
1-1 编写TeacherMapper接口
package com.kuang.dao;
public interface TeacherMapper {
// 获取所有老师信息
List<Teacher> getTeacher();
}
1-2 编写StudentMapper接口配置文件
- 在resources源文件下已创建好的com.kuang.dao包中,编写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.kuang.dao.TeacherMapper">
<!-- 查询所有的老师信息 -->
<select id="getTeacher" resultType="Teacher">
Select * from mybatis.teacher
</select>
</mapper>
12.1.3 创建编写核心配置文件
1.编写db.properties配置文件
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/mybatis?useSSL=true&useUnicode=true&characterEncoding=UTF-8
username=root
pwd=123456
2.编写mybatis-config.xml文件
使用class文件绑定注册mapper接口
<?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: 核心配置文件 -->
<configuration>
<!-- 引入外部配置文件, 优先使用外部配置文件 -->
<properties resource="db.properties"/>
<!-- 设置标准日志输出 -->
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
<!-- 通过给包起别名 -->
<typeAliases>
<package name="com.kuang.pojo"/>
</typeAliases>
<!-- 设置默认环境为开发环境 -->
<environments default="development">
<!-- 设置一道环境为开发环境 -->
<environment id="development">
<!-- transactionManager: 表示事务管理器, 而MyBatis的默认管理器是JDBC-->
<transactionManager type="JDBC"/>
<!-- dataSource: 表示数据源, 主要作用: 连接数据库, MyBatis的默认数据源类型是POOLED,也就是有池的连接 -->
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${pwd}"/>
</dataSource>
</environment>
</environments>
<!-- 绑定接口:使用class文件绑定注册 -->
<mappers>
<mapper class="com.kuang.dao.TeacherMapper"/>
<mapper class="com.kuang.dao.StudentMapper"/>
</mappers>
</configuration>
12.1.4 创建编写测试类
1.编写测试类代码
package com.kuang.dao;
public class MyTest {
@Test
public void getTeacher() {
// 获取sqlSession对象
SqlSession sqlSession = MybatisUtils.getSqlSession();
// 获取TeacherMapper接口(实质是通过反射)
TeacherMapper mapper = sqlSession.getMapper(TeacherMapper.class);
// 获取查询的教师信息集合
List<Teacher> teachers = mapper.getTeacher();
// 使用foreach循环遍历教师信息集合
for (Teacher teacher : teachers) {
// 打印教师信息
System.out.println(teacher);
}
// 下面是以上几行代码的简写形式, 但是并不建议这样写
/*
for (Teacher teacher : sqlSession.getMapper(TeacherMapper.class).getTeacher()) {
System.out.println(teacher);
}
*/
// 关闭sqlSession对象
sqlSession.close();
}
}
2.测试结果
结果:成功查询到所有老师的信息!但学生信息为null值!
12.2 完善基本环境搭建测试
12.2.1 创建编写实体类和工具类
- 与12.1.1 的编写内容相同
12.2.2 创建编写Mapper接口及配置文件
1.编写StudentMapper接口及配置文件
- 与12.1.2中StudentMapper接口及其映射文件的编写相同
2.编写TeacherMapper接口及配置文件
- 在12.1.2中编写的TeacherMapper接口及其映射文件基础上进一步修改
2-1 编写TeacherMapper接口
package com.kuang.dao;
public interface TeacherMapper {
/**
* 获取指定老师下的所有学生及老师的信息
*/
// 使用结果嵌套处理
Teacher getTeacher2(@Param("tid") int id);
// 使用查询嵌套处理
Teacher getTeacher3(@Param("tid") int id);
}
2-2 编写TeacherMapperx.xml文件
1.按照结果嵌套处理
<?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.kuang.dao.TeacherMapper">
<!-- 查询指定老师下的所有学生及老师信息 -->
<!-- 按照结果嵌套查询 -->
<select id="getTeacher2" resultMap="TeacherStudent">
Select s.id sid,s.name sname,t.id tid,t.name tname
from student s,teacher t
where s.tid = t.id and t.id = #{tid}
</select>
<!-- resultMap结果集 -->
<resultMap id="TeacherStudent" type="Teacher">
<result property="id" column="tid"/>
<result property="name" column="tname"/>
<!-- 复杂属性,需要单独处理;
其中association: 代表对象; collection: 代表集合
javaType=""指定属性的类型; 而集合中的泛型信息,要使用ofType获取-->
<collection property="students" ofType="Student">
<result property="id" column="sid"/>
<result property="name" column="sname"/>
<result property="tid" column="tid"/>
</collection>
</resultMap>
</mapper>
2.按照查询嵌套处理
<?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">
<!-- 按照查询嵌套处理 -->
<select id="getTeacher3" resultMap="TeacherStudent2">
Select * from mybatis.teacher where id = #{tid}
</select>
<!-- 结果集映射 -->
<resultMap id="TeacherStudent2" type="Teacher">
<!-- collection: 表示集合,一个老师包含多个学生,即一对多关系;
property="students": 用于注入给Teacher实体类的属性students;
javaType="ArrayList": 用于指定属性students的类型为ArrayList;
ofType="Student":集合中的泛型信息, 使用ofType获取, 这里的集合是值List<Student>,因此值为Student
select="getStudentByTeacherId": 下一条要执行的SQL语句, 这里指下面的查询指定老师的所有学生信息, column="id":通过id查找对应的老师 -->
<collection property="students" javaType="ArrayList" ofType="Student" select="getStudentByTeacherId" column="id"/>
</resultMap>
<!-- 查询指定老师的所有学生信息 -->
<select id="getStudentByTeacherId" resultType="Student">
Select * from mybatis.student where tid = #{tid}
</select>
</mapper>
12.2.3 创建编写核心配置文件
- 与12.1.3核心配置文件的编写相同
12.2.4 创建编写测试类
1.编写测试类代码
package com.kuang.dao;
public class MyTest {
/**
* 查询指定老师下的所有学生及老师信息
*/
// 使用结果嵌套处理
@Test
public void getTeacher2() {
// 获取SqlSession对象
SqlSession sqlSession = MybatisUtils.getSqlSession();
// 获Teacher取Mapper接口
TeacherMapper mapper = sqlSession.getMapper(TeacherMapper.class);
// 通过id获取指定教师信息
Teacher teacher = mapper.getTeacher2(1);
// 打印教师信息
System.out.println(teacher);
// 关闭sqlSession对象
sqlSession.close();
}
// 使用查询嵌套处理
@Test
public void getTeache3() {
sqlSession.close();
// 获取SqlSession对象
SqlSession sqlSession = MybatisUtils.getSqlSession();
// 获Teacher取Mapper接口
TeacherMapper mapper = sqlSession.getMapper(TeacherMapper.class);
// 通过id获取指定教师信息
Teacher teacher = mapper.getTeacher3(1);
// 打印教师信息
System.out.println(teacher);
// 关闭sqlSession对象
sqlSession.close();
}
}
2.测试结果
2-1 按照结果嵌套处理
查询结果:
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)])
结果:查询到了指定老师下的老师及所有学生的信息!
2-2 按照查询嵌套处理
结果:与按照结果嵌套处理相同!
12.3 多对一和一对多使用小结
12.3.1 association的使用
association:关联【多对一】
12.3.2 collection的使用
collection:集合【一对多】
12.3.3 javaType和ofType的区别
- javaType用来指定实体类中属性的类型
- ofType用来指定映射到List或者集合中的pojo类型,泛型中的约束类型!
12.3.4 使用注意点
- 保证SQL的可读性,尽量保证通俗易懂
- 注意一对多和多对一中,属性名和字段的问题
- 如果问题不好排查,可以使用日志,建议使用Log4j
好了,今天的有关 一对多关系处理 的学习就到此结束啦。欢迎小伙伴们积极学习和讨论,喜欢的可以给蜗牛君点个关注,顺便来个一键三连。我们下期见,拜拜啦!