MyBatis实现关联表查询
一、一对一关联
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]]
- }
- }

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属性指定集合中元素的对象类型。
本代码参考自:http://www.cnblogs.com/xdp-gacl/p/4264440.html
测试完全可用。
MyBatis实现关联表查询的更多相关文章
- MyBatis——实现关联表查询
原文:http://www.cnblogs.com/xdp-gacl/p/4264440.html 一.一对一关联 1.1.提出需求 根据班级id查询班级信息(带老师的信息) 1.2.创建表和数据 创 ...
- Mybatis系列(三):Mybatis实现关联表查询
原文链接:http://www.cnblogs.com/xdp-gacl/p/4264440.html 一.一对一关联 1.1.提出需求 根据班级id查询班级信息(带老师的信息) 1.2.创建表和数据 ...
- MyBatis—实现关联表查询
一.一对一关联 1.1.提出需求 根据班级id查询班级信息(带老师的信息) 1.2.创建表和数据 创建一张教师表和班级表,这里我们假设一个老师只负责教一个班,那么老师和班级之间的关系就是一种一对一的关 ...
- mybatis一对一关联表查询
先创建一个表 CREATE TABLE teacher( t_id INT PRIMARY KEY AUTO_INCREMENT, t_name ) ); CREATE TABLE class( c_ ...
- Mybatis源码分析--关联表查询及延迟加载原理(二)
在上一篇博客Mybatis源码分析--关联表查询及延迟加载(一)中我们简单介绍了Mybatis的延迟加载的编程,接下来我们通过分析源码来分析一下Mybatis延迟加载的实现原理. 其实简单来说Myba ...
- 在MyBatis中查询数据、涉及多参数的数据访问操作、插入数据时获取数据自增长的id、关联表查询操作、动态SQL、关于配置MyBatis映射没有代码提示的解决方案
1. 单元测试 在单元测试中,每个测试方法都需要执行相同的前置代码和后置代码,则可以自定义2个方法,分别在这2个方法中执行前置代码和后置代码,并为这2个方法添加@Before和@After注解,然后, ...
- .NetCore中EFCore的使用整理(二)-关联表查询
EF常用处理关联加载的方式有3中:延迟加载(Lazy Loading).贪婪加载 (Eager Loading)以及显示加载. 一.EF Core 1.1 1.当前的版本,还不支持延迟加载(Lazy ...
- SpringBoot Data JPA 关联表查询的方法
SpringBoot Data JPA实现 一对多.多对一关联表查询 开发环境 IDEA 2017.1 Java1.8 SpringBoot 2.0 MySQL 5.X 功能需求 通过关联关系查询商店 ...
- 使用Mybatis进行连表查询、left join---https://blog.csdn.net/jinzhencs/article/details/51980518
使用Mybatis进行连表查询.left join https://blog.csdn.net/jinzhencs/article/details/51980518
随机推荐
- Android 组件和进程的一些关系
1.Service 如果没有单独指定线程的话,那么和主activity是在同一个线程的,就是主线程,那么也不能够在这个service中做耗时操作,否则一定会中断退出. 2.默认情况下,一个Androi ...
- python——连接Oracle数据库
前言 Python自带的模块中有很多操纵文件的.我们可以把文件的数据读出来,经过处理还可以将数据写入文件中.但是对于数据的管理和分析来说,数据库还是专业一些.如果Python能和数据库结合在一起,那么 ...
- 【Spring实战】—— 12 AspectJ报错:error at ::0 can't find referenced pointcut XXX
今天在使用AspectJ进行注解切面时,遇到了一个错误. 切点表达式就是无法识别——详细报错信息如下: Exception can't find referenced pointcut perform ...
- JQuery 菜鸟笔记(一)
什么是JQuery JQuery是一个优秀的javascript类库,jQuery以其简洁.快速等优点征服了众多javascript开发者.jQuery使用户能更方便地处理DOM.events.实现动 ...
- c/c++ string.h
操作数的都是 ( char * )型,操作时不考虑末尾的'\0',操作数必须是指向字符串的指针("a"),不能是字符('a'). size_t strlen( const char ...
- code first 创建和初始化数据库
1.前言 Code First是Entity Framework提供的一种新的编程模型.通过Code First我们可以在还没有建立数据库的情况下就开始编码,然后通过代码对象来生成数据库.当然我们在实 ...
- ios 添加伪闪屏
self.window.rootViewController.view.alpha = ; UIImageView *splashImageView = [[UIImageView alloc]ini ...
- MVC自动绑定整数数组
昨天恰好遇到这个问题,stackoverflow上已经有人回答过了,拿过来在这里做个笔记.当然下面的例子可以修改,我比较喜欢使用ImodelBinder. 自定义模型绑定器 public class ...
- [软件推荐]VMware Workstation 12.1.1多国语言(含简体中文)+激活方法
虚拟机VMware功能强大,使用方便,可以在同一台电脑上安装多个系统(Windows.Linux.OS).虚拟机上的所有操作都不会影响到“实体机”,因此在虚拟机中可以进行很多测试操作,如果某些软件使用 ...
- BZOJ4712 : 洪水
首先不难列出DP方程: $dp[x]=\min(w[x],h[x])$ $h[x]=\sum dp[son]$ 当$w[x]$增加时,显然$dp[x]$不会减少,那么我们求出$dp[x]$的增量$de ...