原文:http://www.cnblogs.com/xdp-gacl/p/4264440.html

一、一对一关联

1.1、提出需求

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

1.2、创建表和数据

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

CREATE TABLE teacher(
t_id INT PRIMARY KEY AUTO_INCREMENT,
t_name VARCHAR(20)
);
CREATE TABLE class(
c_id INT PRIMARY KEY AUTO_INCREMENT,
c_name VARCHAR(20),
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', 1);
INSERT INTO class(c_name, teacher_id) VALUES('class_b', 2);

  

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查询班级信息(带老师的信息)
##1. 联表查询
SELECT * FROM class c,teacher t WHERE c.teacher_id=t.t_id AND c.c_id=1; ##2. 执行两次查询
SELECT * FROM class WHERE c_id=1; //teacher_id=1
SELECT * FROM teacher WHERE t_id=1;//使用上面得到的teacher_id
--> <!--
方式一:嵌套结果:使用嵌套结果映射来处理重复的联合结果的子集
封装联表查询的数据(去除重复的数据)
select * from class c, teacher t where c.teacher_id=t.t_id and c.c_id=1
-->
<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=1;
SELECT * FROM teacher WHERE t_id=1 //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,1);//查询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,1);//查询class表中id为1的记录
//使用SqlSession执行完SQL之后需要关闭SqlSession
sqlSession.close();
System.out.println(clazz);//打印结果:Classes [id=1, name=class_a, teacher=Teacher [id=1, name=teacher1]]
}
}
按 Ctrl+C 复制代码

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(20),
class_id INT
);
INSERT INTO student(s_name, class_id) VALUES('student_A', 1);
INSERT INTO student(s_name, class_id) VALUES('student_B', 1);
INSERT INTO student(s_name, class_id) VALUES('student_C', 1);
INSERT INTO student(s_name, class_id) VALUES('student_D', 2);
INSERT INTO student(s_name, class_id) VALUES('student_E', 2);
INSERT INTO student(s_name, class_id) VALUES('student_F', 2);

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=1
-->
<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=1;
SELECT * FROM teacher WHERE t_id=1 //1 是上一个查询得到的teacher_id的值
SELECT * FROM student WHERE class_id=1 //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,1);//查询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,1);//查询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.1.提出需求 根据班级id查询班级信息(带老师的信息) 1.2.创建表和数据 创建一张教师表和班级表,这里我们假设一个老师只负责教一个班,那么老师和班级之间的关系就是一种一对一的关 ...

  2. Mybatis系列(三):Mybatis实现关联表查询

    原文链接:http://www.cnblogs.com/xdp-gacl/p/4264440.html 一.一对一关联 1.1.提出需求 根据班级id查询班级信息(带老师的信息) 1.2.创建表和数据 ...

  3. MyBatis—实现关联表查询

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

  4. mybatis一对一关联表查询

    先创建一个表 CREATE TABLE teacher( t_id INT PRIMARY KEY AUTO_INCREMENT, t_name ) ); CREATE TABLE class( c_ ...

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

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

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

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

  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进行连表查询、left join---https://blog.csdn.net/jinzhencs/article/details/51980518

    使用Mybatis进行连表查询.left join https://blog.csdn.net/jinzhencs/article/details/51980518

随机推荐

  1. YTU 2991: 链表节点逆置(线性表)

    2991: 链表节点逆置(线性表) 时间限制: 1 Sec  内存限制: 128 MB 提交: 14  解决: 6 题目描述 设计一个算法,将一个带头节点的数据域依次为a1,a2,-,an(n> ...

  2. 一个通用的DAO模型实现增删改查

    首先三个架包: mysql-connector-java-jar commons-dbcp-1.4jar commons-pool-1.5.5jar 导进去: (从上往下一次调用,实现功能) ---- ...

  3. Emag eht htiw Em Pleh 分类: POJ 2015-06-29 18:54 10人阅读 评论(0) 收藏

    Emag eht htiw Em Pleh Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 2937   Accepted: ...

  4. reactjs入门到实战(九)----ajax的应用

    利用外部的jquery: <script type="text/babel"> } }, componentDidMount:function(){ ]['value' ...

  5. 位运算(bit)

    位运算(bit) Time Limit:2000ms   Memory Limit:64MB [题目描述] lyk最近在研究位运算.它发现除了xor,or,and外还有很多运算.它新定义了一种运算符“ ...

  6. JavaScript的循环语句

    JavaScript的循环语句 1.JavaScript的循环语句 (1)for循环语句 - 循环代码块一定的次数: (2)for/in循环语句 - 循环遍历对象的属性: (3)while循环语句 - ...

  7. UVA 12050 - Palindrome Numbers 模拟

    题目大意:给出i,输出第i个镜像数,不能有前导0. 题解:从外层开始模拟 #include <stdio.h> int p(int x) { int sum, i; ;i<=x;i+ ...

  8. Spring MVC 详解(一)

    springmvc是spring的一个模块,提供web层解决方案(基于mvc设计架构),mvc是一个设计模式,在b/s系统的应用: spring 的架构 mvc设计模式 spring MVC的框架 第 ...

  9. 利用jdbc处理oracle大数据---大文件和二进制文件

    一.Oracle中大数据处理 在Oracle中,LOB(Large Object,大型对象)类型的字段现在用得越来越多了.因为这种类型的字段,容量大(最多能容纳4GB的数据),且一个表中可以有多个这种 ...

  10. jquery相对选择器,又叫context选择器,上下文选择器;find()与children()区别

    jquery相对选择器有两个参数,jQuery函数的第二个参数可以指定DOM元素的搜索范围(即以第二个参数指定的内容为容器查找指定元素). 第二个参数的不同的类型,对应的用法如下表所示. 类型 用法 ...