当查询数据分散在多个表中的时候,要一次将结果查出来,这时就需要进行表关联了,将关联之后的结果,映射到Java 对象上,并最终返回给请求端。本文一起来看一下基于Mybatis Plus从多个表中查询关联数据,并映射到结果集上的两种查询方法。




QueryWrapper BaseMapper 关联查询 mybatisplus 关联查询_ci

Mybatis Plus 关联查询和级联查询



两个表关联后,我们有两种返回查询结果集的方式,一种是平铺方式,也就是两个表的字段都放到一个entity中;另一种是在一个entity中持有另一个entity,这就是我们常说的级联查询。

我们举例以班级表和学生表为例,一个班级对应多个学生,一个学生对应一个班级,对应关系就是班级对学生是一对多,学生对班级是一对一(从一个学生的角度去查询,一个学生同一时间只能在一个班级)。

我们先来构造数据。

1、构造两个表,班级表和学生表

-- 构造班级表DROP TABLE IF EXISTS classz;CREATE TABLE classz(id BIGINT(20) NOT NULL COMMENT '主键ID',name VARCHAR(30) NULL DEFAULT NULL COMMENT '班级名称',PRIMARY KEY (id));DROP TABLE IF EXISTS student;CREATE TABLE student(id BIGINT(20) NOT NULL COMMENT '主键ID',cid BIGINT(20),name VARCHAR(30) NULL DEFAULT NULL COMMENT '姓名',PRIMARY KEY (id));

2、初始化表中数据

DELETE FROM classz;INSERT INTO classz (id, name) VALUES(1, '一年一班'),(2, '一年二班');DELETE FROM student;INSERT INTO student (id, cid, name) VALUES(1, 1,'小明'),(2, 1,'小欧');

数据构造了两个班级,小明和小欧都在1班。

如果我们从学生的角度查询学生,并把学生对应的班级也关联出来,那么这两种方式的展示方式,我们先看第一种,平铺式的,也就是所有结果字段都在一个类中。

1、构造entity,用于保存结果

package com.itzhimei.mybatis.plus.model;import com.baomidou.mybatisplus.annotation.TableId;import lombok.Data;/** * @Auther: www.itzhimei.com * @Description: 班级和学生entity */@Datapublic class ClasszAndStudent {    private Long id;    private String name;    private Long stdId;    private Long cid;    private String stdName;}

2、在mapper中构建一个查询方法,两个表关联,字段重名就命名别名,与entity对应上

package com.itzhimei.mybatis.plus.mapper;import com.baomidou.mybatisplus.core.mapper.BaseMapper;import com.itzhimei.mybatis.plus.model.Classz;import com.itzhimei.mybatis.plus.model.ClasszAndStudent;import org.apache.ibatis.annotations.Select;import java.util.List;/** * @Auther: www.itzhimei.com * @Description: */public interface ClasszMapper extends BaseMapper {    /**     * 关联查询     * @return     */    @Select("select a.*,b.id stdId,b.cid, b.name stdName from classz a ,student b where a.id = b.cid and a.id = 1")    List selectClassAndStudents();}

3、测试

/** * @Auther: www.itzhimei.com * @Description: */@RunWith(SpringRunner.class)@SpringBootTestpublic class ClassStudentTest {    @Autowired    private ClasszMapper classzMapper;    @Autowired    private StudentMapper studentMapper;    @Test    public void testSelect() {        List classzs = classzMapper.selectClassAndStudents();        classzs.forEach(System.out::println);    }}

4、输出:

---------------SQL打印输出---------------==>  Preparing: select a.*,b.id stdId,b.cid, b.name stdName from classz a ,student b where a.id = b.cid and a.id = 1 ==> Parameters: <==    Columns: ID, NAME, STDID, CID, STDNAME<==        Row: 1, 一年一班, 1, 1, 小明<==        Row: 1, 一年一班, 2, 1, 小欧<==      Total: 2-------------------代码打印输出----------------------ClasszAndStudent(id=1, name=一年一班, stdId=1, cid=1, stdName=小明)ClasszAndStudent(id=1, name=一年一班, stdId=2, cid=1, stdName=小欧)

我上面说到的平铺式的,就是这种效果:

ClasszAndStudent(id=1, name=一年一班, stdId=1, cid=1, stdName=小明)

另一种就是级联查询方式的返回查询结果。

1、构造实体,用于保存数据

package com.itzhimei.mybatis.plus.model;import com.baomidou.mybatisplus.annotation.TableField;import lombok.Data;import java.util.List;/** * @Auther: www.itzhimei.com * @Description: 学生entity */@Datapublic class Student {    private Long id;    private Long cid;    private String name;    @TableField(exist = false)    private Classz classz;}
package com.itzhimei.mybatis.plus.model;import com.baomidou.mybatisplus.annotation.TableField;import com.baomidou.mybatisplus.annotation.TableId;import lombok.Data;import java.util.List;/** * @Auther: www.itzhimei.com * @Description: 班级entity */@Datapublic class Classz {    private Long id;    private String name;}

2、在StudentMapper中添加一个级联查询方法

package com.itzhimei.mybatis.plus.mapper;import com.baomidou.mybatisplus.core.mapper.BaseMapper;import com.itzhimei.mybatis.plus.model.Classz;import com.itzhimei.mybatis.plus.model.Student;import org.apache.ibatis.annotations.One;import org.apache.ibatis.annotations.Result;import org.apache.ibatis.annotations.Results;import org.apache.ibatis.annotations.Select;import java.util.List;/** * @Auther: www.itzhimei.com * @Description: */public interface StudentMapper extends BaseMapper {    /**     * 一对一的级联查询     * @return     */    @Results(id="id",value = {            @Result(property = "id",column = "id"),            @Result(property = "name",column = "name"),            @Result(property = "cid",column = "cid"),            @Result(property = "classz",column = "cid", one = @One(select = "com.itzhimei.mybatis.plus.mapper.ClasszMapper.selectById"))    })    @Select("select * from student ")    List selectStudentsAndClass();}

注意代码中的注解,其中这一行:

@Result(property = "classz",column = "cid", one = @One(select = "com.itzhimei.mybatis.plus.mapper.ClasszMapper.selectById"))

作用就是执行了ClasszMapper.selectById()方法,用主键查询对应的班级,将查询结果set到了Student实体类中的Classz classz属性中(请看上面Student类中的属性)。

3、测试

package com.itzhimei.mybatis.plus.test;import com.itzhimei.mybatis.plus.mapper.ClasszMapper;import com.itzhimei.mybatis.plus.mapper.StudentMapper;import com.itzhimei.mybatis.plus.model.ClasszAndStudent;import com.itzhimei.mybatis.plus.model.Student;import org.junit.Test;import org.junit.runner.RunWith;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.boot.test.context.SpringBootTest;import org.springframework.test.context.junit4.SpringRunner;import java.util.List;/** * @Auther: www.itzhimei.com * @Description: */@RunWith(SpringRunner.class)@SpringBootTestpublic class ClassStudentTest {    @Autowired    private ClasszMapper classzMapper;    @Autowired    private StudentMapper studentMapper;    @Test    public void testSelectCascade() {        List students = studentMapper.selectStudentsAndClass();        students.forEach(System.out::println);    }}

4、输出

---------------SQL打印输出---------------==>  Preparing: select * from student ==> Parameters: <==    Columns: ID, CID, NAME<==        Row: 1, 1, 小明====>  Preparing: SELECT id,name FROM classz WHERE id=? ====> Parameters: 1(Long)<====    Columns: ID, NAME<====        Row: 1, 一年一班<====      Total: 1<==        Row: 2, 1, 小欧<==      Total: 2-------------------代码打印输出----------------------Student(id=1, cid=1, name=小明, classz=Classz(id=1, name=一年一班))Student(id=2, cid=1, name=小欧, classz=Classz(id=1, name=一年一班))

看代码的输出结果:

Student(id=1, cid=1, name=小明, classz=Classz(id=1, name=一年一班))

Student中包含的Classz也带有数据,是这种Student(Classz)包含一个实体的效果,这就实现了一个一对一级联查询效果。