MyBatis之多表联合查询
在这篇文章里面主要讲解如何在mybatis里面使用一对一、一对多、多表联合查询(类似视图)操作的例子。
注:阅读本文前请先大概看一下之前两篇文章。
一、表结构
班级表class,学生表student,班级学生关系表ClassStudent。
这里一个学生只会在一个班级里面,也就是一对一的关系;一个班级有多个学生,也就是一对多的关系。
结构如下:
CREATE TABLE [dbo].[Class](。
[class_id] [int] NOT NULL,。
[class_name] [varchar](50) NOT NULL,。
CONSTRAINT [PK_Class] PRIMARY KEY CLUSTERED 。
[class_id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]。
) ON [PRIMARY]
CREATE TABLE [dbo].[ClassStudent](。
[class_id] [int] NOT NULL,。
[student_id] [int] NOT NULL。
) ON [PRIMARY]
CREATE TABLE [dbo].[Student](。
[s_id] [int] NOT NULL,。
[s_name] [varchar](50) NOT NULL,。
CONSTRAINT [PK_Student] PRIMARY KEY CLUSTERED 。
[s_id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]。
) ON [PRIMARY]
3张表的数据如下:
insert into Class values(1,'三(1)班')。
insert into Class values(2,'三(2)班')。
insert into Class values(3,'三(3)班')。
insert into Class values(4,'三(4)班')。
insert into Student values(1001,'张三')。
insert into Student values(1002,'李四')。
insert into Student values(1003,'赵五')。
insert into Student values(1004,'王二麻子')。
insert into ClassStudent values(1,1001)。
insert into ClassStudent values(1,1003)。
insert into ClassStudent values(4,1002)。
insert into ClassStudent values(3,1004)。
二、在原项目下新建一个包com.mybatis.sqljoinrelation,在包里面新建一个sqlMapper.xml的映射文件,在项目的mybatis的配置文件conf.xml中对这个sqlMapper.xml进行注册,注册片段如下:
<!-- 注册映射文件 -->。
<mappers>。
<mapper resource="com/mybatis/sqljoinrelation/sqlMapper.xml" />。
</mappers>。
紧接着在原项目下再新建一个包com.mybatis.bean,在里面新建实体类。
学生:
package com.mybatis.bean;。
/**
* 学生(临时)
*/
public class StudentTemp {。
private int studentid;。
private String studentname;。
private Class tempClass;。
public Class getTempClass() {。
return tempClass;。
public void setTempClass(Class tempClass) {。
this.tempClass = tempClass;。
public int getStudentid() {。
return studentid;。
public void setStudentid(int studentid) {。
this.studentid = studentid;。
public String getStudentname() {。
return studentname;。
public void setStudentname(String studentname) {。
this.studentname = studentname;。
@Override
public String toString() {。
return "StudentTemp [studentid=" + studentid + ", studentname="。
+ studentname + ", tempClass=" + tempClass + "]";。
班级:
package com.mybatis.bean;。
/**
* 班级
*/
public class Class {。
private int classid;。
private String classname;。
public int getClassid() {。
return classid;。
public void setClassid(int classid) {。
this.classid = classid;。
public String getClassname() {。
return classname;。
public void setClassname(String classname) {。
this.classname = classname;。
@Override
public String toString() {。
return "Class [classid=" + classid + ", classname=" + classname + "]";。
学生班级视图类:
package com.mybatis.bean;。
public class studentclass {。
private int s_id;。
private String s_name;。
private int class_id;。
private String class_name;。
public int getS_id() {。
return s_id;
public void setS_id(int s_id) {。
this.s_id = s_id;。
public String getS_name() {。
return s_name;
public void setS_name(String s_name) {。
this.s_name = s_name;。
public int getClass_id() {。
return class_id;。
public void setClass_id(int class_id) {。
this.class_id = class_id;。
public String getClass_name() {。
return class_name;。
public void setClass_name(String class_name) {。
this.class_name = class_name;。
@Override
public String toString() {。
return "studentclass [s_id=" + s_id + ", s_name=" + s_name。
+ ", class_id=" + class_id + ", class_name=" + class_name + "]";。
三、查询操作
1、 一对一,查询学生编号等于1001且他所在班级信息。
2、一对多,查询班级编号等于1且包含所有学生信息。
3、类似视图查询学生编号等于1001且他所在班级信息。
sqlMapper.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.mybatis.sqljoinrelation.sqlMapper">。
<!-- 1、 获取某学生以及该学生所在班级的信息 -->。
<!-- 可以显示指出c.class_id,c.class_name,s.s_id,s.s_name列明,
如果用"*"代替,则mybatis会自动匹配resultMap中提供的列名 -->。
<select id="getStudentAndClass" parameterType="int" resultMap="studentClassMap">。
select c.class_id,c.class_name,s.s_id,s.s_name。
from Class c left join ClassStudent cs。
on c.class_id = cs.class_id。
left join Student s。
on cs.student_id = s.s_id。
where s.s_id = #{id}。
</select>。
<!-- resultMap中的type表示返回什么类型的对象 -->。
<resultMap type="com.mybatis.bean.StudentTemp" id="studentClassMap">。
<!-- property 表示com.mybatis.bean.StudentTemp中的属性; column 表示表中的列名 -->。
<id property="studentid" column="s_id" />。
<result property="studentname" column="s_name" />。
<!-- association字面意思关联,这里只专门做一对一关联; property表示是com.mybatis.bean.StudentTemp中的属性名称;
javaType表示该属性是什么类型对象 -->。
<association property="tempClass" javaType="com.mybatis.bean.Class">。
<!-- property 表示com.mybatis.bean.Class中的属性; column 表示表中的列名 -->。
<id property="classid" column="class_id" />。
<result property="classname" column="class_name" />。
</association>。
</resultMap>。
<!-- 2、获取某学生以及该学生所在班级的信息,类似视图实现方式 -->。
<!-- resultType 对应简单类型,也就是实体中的属性名称与数据库表字段名称一模一样;
resultMap 对应复杂类型,属性名称与字段名称不一样可以通过resultMap中property,column进行映射 -->。
<select id="getStudentAndClassView" parameterType="int" resultType="com.mybatis.bean.studentclass">。
select c.class_id,c.class_name,s.s_id,s.s_name。
from Class c left join ClassStudent cs。
on c.class_id = cs.class_id。
left join Student s。
on cs.student_id = s.s_id。
where s.s_id = #{id}。
</select>。
<!-- 3、获取某班级以及班级里面所有学生的信息 -->。
<select id="getClassStudents" parameterType="int" resultMap="classStudentsMap">。
select *
from Class c left join ClassStudent cs。
on c.class_id = cs.class_id。
left join Student s。
on cs.student_id = s.s_id。
where c.class_id = #{id}。
</select>。
<resultMap type="com.mybatis.bean.ClassTemp" id="classStudentsMap">。
<id property="classid" column="class_id"/>。
<result property="classname" column="class_name"/>。
<!-- property表示集合类型属性名称,ofType表示集合中的对象是什么类型 -->。
<collection property="students" ofType="com.mybatis.bean.Student">。
<id property="studentid" column="s_id"/>。
<result property="studentname" column="s_name"/>。
</collection>。
</resultMap>。
</mapper>。
测试代码如下:
一对一与类似视图查询的代码在一起,如下:
package com.mybatis.sqljoinrelation;。
import org.apache.ibatis.session.SqlSession;。
import org.apache.ibatis.session.SqlSessionFactory;。
import com.mybatis.util.MybatisUtils;。
/**
* 一对一
*/
public class testonetoone {。
public static void main(String[] args) {。
SqlSessionFactory factory = MybatisUtils.getFactory();。
SqlSession session = null;。
try {
session = factory.openSession(true);。
//1、StudentTemp。
String statement1 = "com.mybatis.sqljoinrelation.sqlMapper.getStudentAndClass";。
System.out.println(session.selectOne(statement1, 1001));。
//2、用model类型接收数据。
String statement2 = "com.mybatis.sqljoinrelation.sqlMapper.getStudentAndClassView";。
System.out.println(session.selectOne(statement2, 1001));。
} catch (Exception e) {。
e.printStackTrace();。
}finally{
session.close();。
一对多测试代码如下:
package com.mybatis.sqljoinrelation;。
import org.apache.ibatis.session.SqlSession;。
import org.apache.ibatis.session.SqlSessionFactory;。
import com.mybatis.util.MybatisUtils;。
/**
* 一对多
*/
public class testonetomany {。
public static void main(String[] args) {。
SqlSessionFactory factory = MybatisUtils.getFactory();。
SqlSession session = null;。
try {
session = factory.openSession(true);。
//1、StudentTemp。
String statement = "com.mybatis.sqljoinrelation.sqlMapper.getClassStudents";。
System.out.println(session.selectOne(statement, 1));。
} catch (Exception e) {。
e.printStackTrace();。
}finally{
session.close();。
四、sqlMapper.xml需要说明的问题。
1、一对一:<association property="tempClass" javaType="com.mybatis.bean.Class">。
association字面意思关联,这里只专门做一对一关联; property表示是com.mybatis.bean.StudentTemp中的属性名称; javaType表示该属性是什么类型对象。
2、类似视图查询: <select id="getStudentAndClassView" parameterType="int" resultType="com.mybatis.bean.studentclass"> 。
resultType 对应简单类型,也就是实体中的属性名称与数据库表字段名称一模一样;
resultMap 对应复杂类型,属性名称与字段名称不一样可以通过resultMap中property,column进行映射,其中一对一与一对多都是用resultMap来映射。
3、一对多:<collection property="students" ofType="com.mybatis.bean.Student">。
collection字面意思是集合,这里专门做一对多关联 ,property表示集合类型属性名称,ofType表示集合中的对象是什么类型。
4、<select>select * from ...</student>与<select>select 字段1,字段2,字段3... from ...</student>。
可以显示指出c.class_id,c.class_name,s.s_id,s.s_name列明,如果用"*"代替,则mybatis会自动匹配resultMap或者resultType中提供的列名,
如果某对象存在列映射的属性,但是在select 后面找不到这个列,则在返回结果中,该列多映射的值为null。
至此,对于一对一、一对多、视图查询都能很好的解决,主要还是要重点关注第四点说明。
------------------SB要封便封。
MyBatis-Plus之所以被网友称赞,不仅仅是因为他为了简化而生,为了提高效率而开发,而是因为他可以解决多表关联的问题。
一:为简化开发而生的mybatis-plusMyBatis-Plus的基础MyBatis ,他说是从mybatis进化而来的,在 MyBatis 的基础上增强性能,但是不改变根本,为简化开发、提高效率而生的mybatis-puls,由于它的只加强不改变,让它拥有了无侵入性能,这个特性可以让它在介入工程时,不会有卡顿现象,它还有强大的 CRUD 操作,可以满足用户各类需求,它还有性能分析拦截器,如果超过指定时间机会停止运行,可以及时发现问题解决问题。
二:mybatis-puls实现实体类操作多表mybatis-puls可以通过业务创建多个表,并且将这些表结合起来,建立实体关系方式,实现一对多实体查询,方便承载账户信息,它的SQL可以使代码拥有极好的可维护性,可以利用数据库的缓存,提高性能。
三:mybatis-puls 方便数据分析管理mybatis-puls可以快速集成多数据源,可以最简洁的完成数据库操作分析,引入 lombok 依赖,进而简化代码,减少使用 gette方法,不需要编写xml文件,简单方便快捷,MyBatis-Plus 的代码生成器是AutoGenerator,它可以最大程度提高开发效率,布局全局信息,配置数据源信息,最大程度简化代码数据,只做切换数据源,不限制用户具体操作。
可以通过关系映射查询出来 请看下面 在mybatis中,没有级联的概念,但是可以利用集合来实现类似的功能。 mybatis3.0添加了association和collection标签专门用于对多个相关实体类数据进行级联查询,但仍不支持多个相关实体类数据的级联保存。
mybatis 对结果是很宽松的,有这个“结果”的对象,就可以返回 List<查询结果对象> 这样的集合。
select a.楼层, b.区域, c.专柜 FROM a LEFT JOIN ................。
select B.name,B.age,A.name from B表 B left join A表 A on B.a_id = A.id。