一、一对一关联

1.1、提出需求

  根据班级id查询班级信息(带老师的信息)

1.2、创建表和数据

  创建一张教师表和班级表,这里我们假设一个老师只负责教一个班,那么老师和班级之间的关系就是一种一对一的关系。

 CREATE TABLE teacher(
t_id INT PRIMARY KEY AUTO_INCREMENT,
t_name VARCHAR()
);
CREATE TABLE class(
c_id INT PRIMARY KEY AUTO_INCREMENT,
c_name VARCHAR(),
teacher_id INT
);
ALTER TABLE class ADD CONSTRAINT fk_teacher_id FOREIGN KEY (teacher_id) REFERENCES teacher(t_id); INSERT INTO teacher(t_name) VALUES('teacher1');
INSERT INTO teacher(t_name) VALUES('teacher2'); INSERT INTO class(c_name, teacher_id) VALUES('class_a', );
INSERT INTO class(c_name, teacher_id) VALUES('class_b', );

 表之间的关系如下:

  

1.3、定义实体类

  1、Teacher类,Teacher类是teacher表对应的实体类。

 package me.gacl.domain;

 /**
* @author gacl
* 定义teacher表对应的实体类
*/
public class Teacher { //定义实体类的属性,与teacher表中的字段对应
private int id; //id===>t_id
private String name; //name===>t_name public int getId() {
return id;
} public void setId(int id) {
this.id = id;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} @Override
public String toString() {
return "Teacher [id=" + id + ", name=" + name + "]";
}
}

2、Classes类,Classes类是class表对应的实体类

 package me.gacl.domain;

 /**
* @author gacl
* 定义class表对应的实体类
*/
public class Classes { //定义实体类的属性,与class表中的字段对应
private int id; //id===>c_id
private String name; //name===>c_name /**
* class表中有一个teacher_id字段,所以在Classes类中定义一个teacher属性,
* 用于维护teacher和class之间的一对一关系,通过这个teacher属性就可以知道这个班级是由哪个老师负责的
*/
private Teacher teacher; public int getId() {
return id;
} public void setId(int id) {
this.id = id;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public Teacher getTeacher() {
return teacher;
} public void setTeacher(Teacher teacher) {
this.teacher = teacher;
} @Override
public String toString() {
return "Classes [id=" + id + ", name=" + name + ", teacher=" + teacher+ "]";
}
}

1.4、定义sql映射文件classMapper.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,namespace的值习惯上设置成包名+sql映射文件名,这样就能够保证namespace的值是唯一的
例如namespace="me.gacl.mapping.classMapper"就是me.gacl.mapping(包名)+classMapper(classMapper.xml文件去除后缀)
-->
<mapper namespace="me.gacl.mapping.classMapper"> <!--
根据班级id查询班级信息(带老师的信息)
##. 联表查询
SELECT * FROM class c,teacher t WHERE c.teacher_id=t.t_id AND c.c_id=; ##. 执行两次查询
SELECT * FROM class WHERE c_id=; //teacher_id=1
SELECT * FROM teacher WHERE t_id=;//使用上面得到的teacher_id
--> <!--
方式一:嵌套结果:使用嵌套结果映射来处理重复的联合结果的子集
封装联表查询的数据(去除重复的数据)
select * from class c, teacher t where c.teacher_id=t.t_id and c.c_id=
-->
<select id="getClass" parameterType="int" resultMap="ClassResultMap">
select * from class c, teacher t where c.teacher_id=t.t_id and c.c_id=#{id}
</select>
<!-- 使用resultMap映射实体类和字段之间的一一对应关系 -->
<resultMap type="me.gacl.domain.Classes" id="ClassResultMap">
<id property="id" column="c_id"/>
<result property="name" column="c_name"/>
<association property="teacher" javaType="me.gacl.domain.Teacher">
<id property="id" column="t_id"/>
<result property="name" column="t_name"/>
</association>
</resultMap> <!--
方式二:嵌套查询:通过执行另外一个SQL映射语句来返回预期的复杂类型
SELECT * FROM class WHERE c_id=;
SELECT * FROM teacher WHERE t_id= //1 是上一个查询得到的teacher_id的值
-->
<select id="getClass2" parameterType="int" resultMap="ClassResultMap2">
select * from class where c_id=#{id}
</select>
<!-- 使用resultMap映射实体类和字段之间的一一对应关系 -->
<resultMap type="me.gacl.domain.Classes" id="ClassResultMap2">
<id property="id" column="c_id"/>
<result property="name" column="c_name"/>
<association property="teacher" column="teacher_id" select="getTeacher"/>
</resultMap> <select id="getTeacher" parameterType="int" resultType="me.gacl.domain.Teacher">
SELECT t_id id, t_name name FROM teacher WHERE t_id=#{id}
</select> </mapper>

在conf.xml文件中注册classMapper.xml

 <mappers>
<!-- 注册classMapper.xml文件,
classMapper.xml位于me.gacl.mapping这个包下,所以resource写成me/gacl/mapping/classMapper.xml-->
<mapper resource="me/gacl/mapping/classMapper.xml"/>
</mappers>

1.5、编写单元测试代码

 package me.gacl.test;

 import me.gacl.domain.Classes;
import me.gacl.util.MyBatisUtil;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test; public class Test3 { @Test
public void testGetClass(){
SqlSession sqlSession = MyBatisUtil.getSqlSession();
/**
* 映射sql的标识字符串,
* me.gacl.mapping.classMapper是classMapper.xml文件中mapper标签的namespace属性的值,
* getClass是select标签的id属性值,通过select标签的id属性值就可以找到要执行的SQL
*/
String statement = "me.gacl.mapping.classMapper.getClass";//映射sql的标识字符串
//执行查询操作,将查询结果自动封装成Classes对象返回
Classes clazz = sqlSession.selectOne(statement,);//查询class表中id为1的记录
//使用SqlSession执行完SQL之后需要关闭SqlSession
sqlSession.close();
System.out.println(clazz);//打印结果:Classes [id=1, name=class_a, teacher=Teacher [id=1, name=teacher1]]
} @Test
public void testGetClass2(){
SqlSession sqlSession = MyBatisUtil.getSqlSession();
/**
* 映射sql的标识字符串,
* me.gacl.mapping.classMapper是classMapper.xml文件中mapper标签的namespace属性的值,
* getClass2是select标签的id属性值,通过select标签的id属性值就可以找到要执行的SQL
*/
String statement = "me.gacl.mapping.classMapper.getClass2";//映射sql的标识字符串
//执行查询操作,将查询结果自动封装成Classes对象返回
Classes clazz = sqlSession.selectOne(statement,);//查询class表中id为1的记录
//使用SqlSession执行完SQL之后需要关闭SqlSession
sqlSession.close();
System.out.println(clazz);//打印结果:Classes [id=1, name=class_a, teacher=Teacher [id=1, name=teacher1]]
}
}

1.6、MyBatis一对一关联查询总结

  MyBatis中使用association标签来解决一对一的关联查询,association标签可用的属性如下:

  • property:对象属性的名称
  • javaType:对象属性的类型
  • column:所对应的外键字段名称
  • select:使用另一个查询封装的结果

二、一对多关联

2.1、提出需求

  根据classId查询对应的班级信息,包括学生,老师

2.2、创建表和数据

  在上面的一对一关联查询演示中,我们已经创建了班级表和教师表,因此这里再创建一张学生表

 CREATE TABLE student(
s_id INT PRIMARY KEY AUTO_INCREMENT,
s_name VARCHAR(),
class_id INT
);
INSERT INTO student(s_name, class_id) VALUES('student_A', );
INSERT INTO student(s_name, class_id) VALUES('student_B', );
INSERT INTO student(s_name, class_id) VALUES('student_C', );
INSERT INTO student(s_name, class_id) VALUES('student_D', );
INSERT INTO student(s_name, class_id) VALUES('student_E', );
INSERT INTO student(s_name, class_id) VALUES('student_F', );

2.3、定义实体类

  1、Student类

 package me.gacl.domain;

 /**
* @author gacl
* 定义student表所对应的实体类
*/
public class Student { //定义属性,和student表中的字段对应
private int id; //id===>s_id
private String name; //name===>s_name public int getId() {
return id;
} public void setId(int id) {
this.id = id;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} @Override
public String toString() {
return "Student [id=" + id + ", name=" + name + "]";
}
}

2、修改Classes类,添加一个List<Student> students属性,使用一个List<Student>集合属性表示班级拥有的学生,如下:

 package me.gacl.domain;

 import java.util.List;

 /**
* @author gacl
* 定义class表对应的实体类
*/
public class Classes { //定义实体类的属性,与class表中的字段对应
private int id; //id===>c_id
private String name; //name===>c_name /**
* class表中有一个teacher_id字段,所以在Classes类中定义一个teacher属性,
* 用于维护teacher和class之间的一对一关系,通过这个teacher属性就可以知道这个班级是由哪个老师负责的
*/
private Teacher teacher;
//使用一个List<Student>集合属性表示班级拥有的学生
private List<Student> students; public int getId() {
return id;
} public void setId(int id) {
this.id = id;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public Teacher getTeacher() {
return teacher;
} public void setTeacher(Teacher teacher) {
this.teacher = teacher;
} public List<Student> getStudents() {
return students;
} public void setStudents(List<Student> students) {
this.students = students;
} @Override
public String toString() {
return "Classes [id=" + id + ", name=" + name + ", teacher=" + teacher
+ ", students=" + students + "]";
}
}

2.4、修改sql映射文件classMapper.xml

  添加如下的SQL映射信息

 <!--
根据classId查询对应的班级信息,包括学生,老师
-->
<!--
方式一: 嵌套结果: 使用嵌套结果映射来处理重复的联合结果的子集
SELECT * FROM class c, teacher t,student s WHERE c.teacher_id=t.t_id AND c.C_id=s.class_id AND c.c_id=
-->
<select id="getClass3" parameterType="int" resultMap="ClassResultMap3">
select * from class c, teacher t,student s where c.teacher_id=t.t_id and c.C_id=s.class_id and c.c_id=#{id}
</select>
<resultMap type="me.gacl.domain.Classes" id="ClassResultMap3">
<id property="id" column="c_id"/>
<result property="name" column="c_name"/>
<association property="teacher" column="teacher_id" javaType="me.gacl.domain.Teacher">
<id property="id" column="t_id"/>
<result property="name" column="t_name"/>
</association>
<!-- ofType指定students集合中的对象类型 -->
<collection property="students" ofType="me.gacl.domain.Student">
<id property="id" column="s_id"/>
<result property="name" column="s_name"/>
</collection>
</resultMap> <!--
方式二:嵌套查询:通过执行另外一个SQL映射语句来返回预期的复杂类型
SELECT * FROM class WHERE c_id=;
SELECT * FROM teacher WHERE t_id= //1 是上一个查询得到的teacher_id的值
SELECT * FROM student WHERE class_id= //1是第一个查询得到的c_id字段的值
-->
<select id="getClass4" parameterType="int" resultMap="ClassResultMap4">
select * from class where c_id=#{id}
</select>
<resultMap type="me.gacl.domain.Classes" id="ClassResultMap4">
<id property="id" column="c_id"/>
<result property="name" column="c_name"/>
<association property="teacher" column="teacher_id" javaType="me.gacl.domain.Teacher" select="getTeacher2"></association>
<collection property="students" ofType="me.gacl.domain.Student" column="c_id" select="getStudent"></collection>
</resultMap> <select id="getTeacher2" parameterType="int" resultType="me.gacl.domain.Teacher">
SELECT t_id id, t_name name FROM teacher WHERE t_id=#{id}
</select> <select id="getStudent" parameterType="int" resultType="me.gacl.domain.Student">
SELECT s_id id, s_name name FROM student WHERE class_id=#{id}
</select>

2.5、编写单元测试代码

 package me.gacl.test;

 import me.gacl.domain.Classes;
import me.gacl.util.MyBatisUtil;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test; public class Test4 { @Test
public void testGetClass3(){
SqlSession sqlSession = MyBatisUtil.getSqlSession();
/**
* 映射sql的标识字符串,
* me.gacl.mapping.classMapper是classMapper.xml文件中mapper标签的namespace属性的值,
* getClass3是select标签的id属性值,通过select标签的id属性值就可以找到要执行的SQL
*/
String statement = "me.gacl.mapping.classMapper.getClass3";//映射sql的标识字符串
//执行查询操作,将查询结果自动封装成Classes对象返回
Classes clazz = sqlSession.selectOne(statement,);//查询class表中id为1的记录
//使用SqlSession执行完SQL之后需要关闭SqlSession
sqlSession.close();
//打印结果:Classes [id=1, name=class_a, teacher=Teacher [id=1, name=teacher1], students=[Student [id=1, name=student_A], Student [id=2, name=student_B], Student [id=3, name=student_C]]]
System.out.println(clazz);
} @Test
public void testGetClass4(){
SqlSession sqlSession = MyBatisUtil.getSqlSession();
/**
* 映射sql的标识字符串,
* me.gacl.mapping.classMapper是classMapper.xml文件中mapper标签的namespace属性的值,
* getClass4是select标签的id属性值,通过select标签的id属性值就可以找到要执行的SQL
*/
String statement = "me.gacl.mapping.classMapper.getClass4";//映射sql的标识字符串
//执行查询操作,将查询结果自动封装成Classes对象返回
Classes clazz = sqlSession.selectOne(statement,);//查询class表中id为1的记录
//使用SqlSession执行完SQL之后需要关闭SqlSession
sqlSession.close();
//打印结果:Classes [id=1, name=class_a, teacher=Teacher [id=1, name=teacher1], students=[Student [id=1, name=student_A], Student [id=2, name=student_B], Student [id=3, name=student_C]]]
System.out.println(clazz);
}
}

2.6、MyBatis一对多关联查询总结

  MyBatis中使用collection标签来解决一对多的关联查询,ofType属性指定集合中元素的对象类型。

MyBatis总结-实现关联表查询的更多相关文章

  1. Mybatis学习——一对一关联表查询

    1.SQL语句建表 CREATE TABLE teacher( t_id ) ); CREATE TABLE class( c_id ), teacher_id INT ); ALTER TABLE ...

  2. 7.Mybatis关联表查询(这里主要讲的是一对一和一对多的关联查询)

    在Mybatis中的管理表查询这里主要介绍的是一对一和一对多的关联查询的resultMap的管理配置查询,当然你也可以用包装类来实现.不过这里不说,做关联查询的步骤可以简单的总结为以下的几步: 1.分 ...

  3. Mybatis源码分析--关联表查询及延迟加载原理(二)

    在上一篇博客Mybatis源码分析--关联表查询及延迟加载(一)中我们简单介绍了Mybatis的延迟加载的编程,接下来我们通过分析源码来分析一下Mybatis延迟加载的实现原理. 其实简单来说Myba ...

  4. 在MyBatis中查询数据、涉及多参数的数据访问操作、插入数据时获取数据自增长的id、关联表查询操作、动态SQL、关于配置MyBatis映射没有代码提示的解决方案

    1. 单元测试 在单元测试中,每个测试方法都需要执行相同的前置代码和后置代码,则可以自定义2个方法,分别在这2个方法中执行前置代码和后置代码,并为这2个方法添加@Before和@After注解,然后, ...

  5. MyBatis中实现多表查询

    如果查询的数据量大,推荐使用N+1次查询.数据量少使用联合查询... 一. 1.Mybatis是实现多表查询方式 1.1  业务装配:对两个表编写单表查询语句,在业务(Service)把查询的两表结果 ...

  6. MyBatis学习之多表查询

    一对多需求:即一张表class中又含有多张表(teacher,student)内容.现根据class_id 来获取对应的班级信息(包括学生和老师信息) 方式一:嵌套结果 使用嵌套结果映射来处理重复的联 ...

  7. .NetCore中EFCore的使用整理(二)-关联表查询

    EF常用处理关联加载的方式有3中:延迟加载(Lazy Loading).贪婪加载 (Eager Loading)以及显示加载. 一.EF Core  1.1 1.当前的版本,还不支持延迟加载(Lazy ...

  8. SpringBoot Data JPA 关联表查询的方法

    SpringBoot Data JPA实现 一对多.多对一关联表查询 开发环境 IDEA 2017.1 Java1.8 SpringBoot 2.0 MySQL 5.X 功能需求 通过关联关系查询商店 ...

  9. MyBatis实现关联表查询

    一.一对一关联 1.1.提出需求 根据班级id查询班级信息(带老师的信息) 1.2.创建表和数据 创建一张教师表和班级表,这里我们假设一个老师只负责教一个班,那么老师和班级之间的关系就是一种一对一的关 ...

随机推荐

  1. Deep Learning 学习随记(五)深度网络--续

    前面记到了深度网络这一章.当时觉得练习应该挺简单的,用不了多少时间,结果训练时间真够长的...途中debug的时候还手贱的clear了一下,又得从头开始运行.不过最终还是调试成功了,sigh~ 前一篇 ...

  2. XML有哪些解析方式有何优缺点?xml有哪些解析技术?区别是什么?

    有DOM,SAX,STAX等 (1):DOM:处理大型文件时其性能下降的非常厉害.这个问题是由DOM的树结构所造成的,这种结构占用的内存较多,而且DOM必须在解析文件之前把整个文档装入内存,适合对XM ...

  3. ios strong weak 的区别 与 理解

    先一句话总结:strong类保持他们拥有对象的活着,weak类他们拥有的对象被人家一牵就牵走,被人家一干就干死.(strong是一个好大哥所以strong,呵呵,weak是一个虚大哥所以weak,呵呵 ...

  4. Ubuntu1404+Django1.9+Apache2.4部署配置1安装

    关于Ubuntu环境下的文章很少,搜索一些问题比较麻烦,这里将别人的做法和自己做的整合一下.这篇文章主要讲解基础的安装,至于Django1.9如何部署到Apache2.4请转到下一篇博文http:// ...

  5. 【POJ1417】【带标记并查集+DP】True Liars

    Description After having drifted about in a small boat for a couple of days, Akira Crusoe Maeda was ...

  6. underscorejs-countBy学习

    2.20 countBy 2.20.1 语法 _.countBy(list, iteratee, [context]) 2.20.2 说明 排序一个列表组成一个组,并且返回各组中的对象的数量的计数.类 ...

  7. 验证视图状态MAC失败解决方案

    验证视图状态 mac 失败.如果此应用程序由网络场或群集承载 请确保 machinekey 配置指定了相同的 validationkey 和验证算法.不能在群集中使用 autogenerate. 总是 ...

  8. gdb小结

    testGdb.c #include<stdio.h> int getSum(int a,int b){ printf("a+b=%d\n",a+b); return ...

  9. JavaScript 获取Select标签选中的项

    <select name="select1" id="select1" onchange=setInput()> <option value= ...

  10. dedecms织梦导航栏二级菜单的实现方法

    dede导航下拉菜单,一级栏目增加二级下拉菜单   使用dedecms5.6——5.7 将这段代码贴到templets\default\head.htm文件里<!-- //二级子类下拉菜单,考虑 ...