上次我们讲到了MyBatis的一对一关系的表示,简单回顾一下一对一关系就是一个学生只有一个学生证。那么什么是一对多关系呢?一个学生有多个课程这就是一对多的关系。我们结合上一章中的学生和学生证,在此基础上新增一个课程表和课程成绩表。学生对应课程表是一对多的关系,在学生确定的情况下课程表对应课程成绩是一对一的关系。我们先来看看我们所假设的场景数据结构的设计。

数据库的ER图如下(因为对数据库还处于菜鸟阶段……所以可能ER图绘制有误,但不影响我们讲解MyBatis一对多关系的级联):

再看看数据库的物理模型包含哪些字段:

数据库的设计就差不多了,接下来是设计我们的POJO类:

首先是Student类:

 package day_8_mybatis.pojo;

 import java.util.List;

 /**
* @author turbo
*
* 2016年11月4日
*/
public class Student {
private int id;
private String name;
private String sex;
private SelfCard selfCard;  //学生和学生证是一对一的关系,所以存放一个对学生证类的引用
private List<CourseScore> courseScoreList;  //我们在一开始就提到过学生和课程是一对多的关系,所以学生POJO类中对课程类字段就是一个List用来存放学生的课程成绩。
//省略set/get方法
}

注意,我们有一个List字段是对课程成绩的引用而不是课程的引用。为什么呢?因为在我们数据库设计中,学生和课程是通过课程成绩联系起来的。

接着是我们的CourseScore类:

 package day_8_mybatis.pojo;

 /**
* @author turbo
*
* 2016年11月4日
*/
public class CourseScore {
private int id;
private int studentId;
private Course course;  //在学生id确认的情况下,课程和成绩是一对一的关系。
private String score;
//省略set/get方法
}

最后是Course类:

 package day_8_mybatis.pojo;

 /**
* @author turbo
*
* 2016年11月4日
*/
public class Course {
private int id;
private String courseName;
private String note;
//省略set/get方法
}

现在我们是要通过一个学生ID,就能查询出这个学生的课程、以及对应课程的成绩。这个怎么来实现呢?在使用MyBatis为我们提供的级联前,我们先来梳理一下从逻辑上是怎么一步一步查询出来的。

我们要通过学生id查询出学生的基本信息(包括课程以及对应的成绩),但在学生POJO类中有一个对课程成绩的List引用(暂时忽略学生证),也就是说我们无法一条简单的sql语句(无join的sql语句)查询出结果。但是!我们可以通过student_id在课程成绩表中查询出该学生的相应课程id(注意此时还是id),但我们此时还是没办法知道具体的课程名,再利用我们上一步中student_id查询出的course_id通过课程表再来查询出对应的课程名。重新梳理一下:

  1. 通过student_id在t_student表中查询学生基本信息(name,sex)
  2. 通过student_id在t_course_score表中查询学生对应的course_id
  3. 通过course_id在t_course表中查询课程

那我们现在就从最底层做起,也就是通过course_id查询出具体课程,因为这不会涉及到其他表。

 package day_8_mybatis.mapper;

 import day_8_mybatis.pojo.Course;

 /**
* @author turbo
*
* 2016年11月4日
*/
public interface CourseMapper {
Course getCourse(int id);  //此id为course_id
}

再来看看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="day_8_mybatis.mapper.CourseMapper">
<select id="getCourse" parameterType="int" resultType="day_8_mybatis.pojo.Course">
select id, course_name as courseName, note from t_course where id = #{id}
</select>
</mapper>

现在已经写好了通过course_id来查询出具体课程。那么就是倒着走到第2步,通过student_id在t_course_score表中查询学生对应的course_id,在最开始说过,在学生确定的情况下,课程和课程成绩是一对一的关系,关于一对一的关系我们在上一篇已经讲过,不妨再重温一下。

 package day_8_mybatis.mapper;

 import day_8_mybatis.pojo.CourseScore;

 /**
* @author turbo
*
* 2016年11月4日
*/
public interface CourseScoreMapper {
CourseScore findCourseScoreByStudentId(int id);
}

再来看看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="day_8_mybatis.mapper.CourseScoreMapper">
<resultMap id="courseScoreMap" type="day_8_mybatis.pojo.CourseScore">
<id property="id" column="id"/>
<result property="studentId" column="student_id"/>
<result property="score" column="score"/>
<association property="course" column="course_id" select="day_8_mybatis.mapper.CourseMapper.getCourse" />  <!--将查询出来的course_id交给CouseMapper来查询出具体课程信息-->
</resultMap> <select id="findCourseScoreByStudentId" parameterType="int" resultMap="courseScoreMap">
select id, student_id, course_id, score from t_course_score where student_id = #{id}
</select>
</mapper>

最后一步,也就是第1步,才进入正题MyBatis的一对多collection级联关系。

 package day_8_mybatis.mapper;

 import day_8_mybatis.pojo.Student;

 /**
* @author turbo
*
* 2016年11月4日
*/
public interface StudentMapper {
Student getStudent(int id);
}

关键在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="day_8_mybatis.mapper.StudentMapper">
<resultMap type="day_8_mybatis.pojo.Student" id="studentMap">
<id property="id" column="id"/>
<result property="name" column="name"/>
<result property="sex" column="sex"/>
<association property="selfCard" column="id" select="day_8_mybatis.mapper.SelfCardMapper.findSelfCardByStudentId"/>
<collection property="courseScoreList" column="id" select="day_8_mybatis.mapper.CourseScoreMapper.findCourseScoreByStudentId" />
</resultMap>
<select id="getStudent" parameterType="int" resultMap="studentMap">
select id, name, sex from t_student where id = #{id}
</select>
</mapper>

请好好仔细品味品味,仔细回顾整个查询的逻辑过程。collection就是MyBatis为我们提供的第二个级联关系——一对多。

最后上我们的测试代码:

 package day_8_mybatis;

 import java.io.IOException;
import java.io.InputStream; import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession; import day_8_mybatis.mapper.StudentMapper;
import day_8_mybatis.pojo.Student;
import day_8_mybatis.util.SessionFactory2; /**
* 客户端
* @author turbo
*
* 2016年11月4日
*/
public class Main { /**
* @param args
* @throws IOException
*/
public static void main(String[] args) throws Exception {
String resource = "day_8_mybatis/mybatis-config.xml"; //获取mybatis配置文件路径
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSession sqlSession = SessionFactory2.getInstance(inputStream).openSession();
StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
Student student = studentMapper.getStudent(1);
System.out.println("学生:" + student.getName() + " 课程:" + student.getCourseScoreList().get(0).getCourse().getCourseName() + " 分数:" + student.getCourseScoreList().get(0).getScore()); } }

//还是把day_8_mybatis.util.SessionFactory2代码贴出来吧,SqlSessionFactory用到了单例模式,这也是MyBatis官方文档所提倡的,具体可以移步之前写的几个关键类的作用域问题,《SqlSessionFactoryBuilder、SqlSessionFactory、SqlSession作用域(Scope)和生命周期》,也可移步至《单例模式》《再说单例模式的线程安全问题》了解单例模式。

 package day_8_mybatis.util;

 import java.io.InputStream;

 import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder; /**
* @author turbo
*
* 2016年10月26日
*/
public class SessionFactory2 {
private static SqlSessionFactory sqlSessionFactory; public static synchronized SqlSessionFactory getInstance(InputStream inputStream){
if (null == sqlSessionFactory){
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
} return sqlSessionFactory;
}
}

MyBatis之级联——一对多关系的更多相关文章

  1. Springboot整合Mybatis实现级联一对多CRUD操作

    在关系型数据库中,随处可见表之间的连接,对级联的表进行增删改查也是程序员必备的基础技能.关于Spring Boot整合Mybatis在之前已经详细写过,不熟悉的可以回顾Spring Boot整合Myb ...

  2. Spring Boot整合Mybatis完成级联一对多CRUD操作

    在关系型数据库中,随处可见表之间的连接,对级联的表进行增删改查也是程序员必备的基础技能.关于Spring Boot整合Mybatis在之前已经详细写过,不熟悉的可以回顾Spring Boot整合Myb ...

  3. 0050 MyBatis关联映射--一对多关系

    一对多关系更加常见,比如用户和订单,一个用户可以有多个订单 DROP TABLE IF EXISTS customer; /*用户表*/ CREATE TABLE customer( `pk` INT ...

  4. mybatis之级联关系(一对一、一对多)

    0. 表结构 1. 准备工作 1.1 配置文件等信息,请参考  myBatis之入门示例 1.2 entity 1.2.1 TPersonInfo.java package com.blueStarW ...

  5. Mybatis框架中实现双向一对多关系映射

    学习过Hibernate框架的伙伴们很容易就能简单的配置各种映射关系(Hibernate框架的映射关系在我的blogs中也有详细的讲解),但是在Mybatis框架中我们又如何去实现 一对多的关系映射呢 ...

  6. [NHibernate]一对多关系(级联删除,级联添加)

    目录 写在前面 文档与系列文章 一对多关系 一个例子 级联删除 级联保存 总结 写在前面 在前面的文章中,我们只使用了一个Customer类进行举例,而在客户.订单.产品中它们的关系,咱们并没有涉及, ...

  7. MyBatis日记(五):一对一关系,一对多关系

    一对一关系: 首先在数据库中新增地址表(t_address)用于存储人员的地址信息: CREATE TABLE `t_address` ( `id` ) NOT NULL AUTO_INCREMENT ...

  8. MyBatis加强(1)~myBatis对象关系映射(多对一关系、一对多关系)、延迟/懒加载

    一.myBatis对象关系映射(多对一关系.一对多关系) 1.多对一关系: ---例子:多个员工同属于一个部门. (1)myBatis发送 额外SQL: ■ 案例:员工表通过 dept_id 关联 部 ...

  9. MyBatis之级联小结

    在这之前我们知道了MyBatis为我们提供了三种级联:一对一关系(assocation).一对多关系(collection).鉴别器(discriminator).在最后一个鉴别器例子中,看到了当层级 ...

随机推荐

  1. IOS开发创建开发证书及发布App应用(六)——打包应用

    6.打包应用 如下图,生成之后点击下面红框的按钮,按时间排序,然后点最新的一次生成 从右侧生成日志中找到如下图红框标识的部分,找到 -output ,把下面浅蓝色选中,这是app生成的文件夹路径 点击 ...

  2. C#调用webbrowser,阻止弹出新HTML页面

    参考资料: 1.C#调用webbrowser,阻止弹出新IE窗口 http://www.cnblogs.com/blindman/p/3819649.html 2.[WPF]监听WPF的WebBrow ...

  3. setInterval定时器

    <!DOCTYPE html><html> <head> <meta charset="UTF-8"> <title>& ...

  4. ubuntu 12.04 x86_64:java.lang.UnsatisfiedLinkError: Could not load SWT library. Reasons

    sy@sy-Aspire-:~$ .0_155965261/configuration/.log !SESSION -- ::39.595 ------------------------------ ...

  5. Andorid开发中如何去除标题栏title

    有两种方法可以去除标题栏的title. 1.在代码中实现 在setContentView()方法之前加上这一句 requestWindowFeature(Window.FEATURE_NO_TITLE ...

  6. Android IPC机制全解析<二>

    在AIDL文件中并不是所有的数据类型都可以使用,AIDL支持的数据类型如下: 基本数据类型(int.long.char.boolean.double等) String和CharSequence Lis ...

  7. Ubuntu 重装 mysql

    我另篇blog有提到修改完my.cnf文件后mysql server重新启动失败,就是说mysql server启动不起来了,于是我就想到重装再试试,没想到就好了. 重装mysql之前需要卸载干净,删 ...

  8. html5脚本编程

    (1)跨文档消息传递,XDM.指的是来自不同域的页面间传递消息. XDM的核心是postMessage();向另一个地方传递数据,指是包含在当前页面中的iframe元素,由当前页面弹出的窗口. var ...

  9. CSS清除float浮动

    一.浮动产生原因   -   TOP 一般浮动是什么情况呢?一般是一个盒子里使用了CSS float浮动属性,导致父级对象盒子不能被撑开,这样CSS float浮动就产生了. 本来两个黑色对象盒子是在 ...

  10. 【2017-04-21】Ado.Nte属性扩展

    通过对数据库表的封装,对该表的属性进行扩展. 1.例如:表中的性别是bool类,要实现显示给用户看的为“男.女” 2.通过表中的生日datetime类,来实现显示给用户看的年月日,自动计算年龄. 3. ...