MyBatis多表查询

目录

1. 多表关系回顾

2. 一对一查询

2.1 一对一多表查询方式一:基于标签进行手动结果映射封装 

2.2 一对一多表查询方式二 - 通过标签来封装属性中所关联的对象

3. 一对多查询

4. 多对多查询


1. 多表关系回顾

MyBatis多表查询_第1张图片

  • 在项目开发当中一对一关系的表不常见,因为一对一关系的两张表通常会合并为一张表。

2. 一对一查询

MyBatis多表查询_第2张图片

MyBatis多表查询_第3张图片

一张表对应一个实体类,一个实体类对应一个Mapper接口。 

例如:查询菜品,同时查询出该菜品所属的分类。

分析:查询菜品是主查询,因此将结果封装到菜品当中,直接在菜品类的属性当中声明一个菜品分类的对象。 

Mybatis多表查询的难点是难在于怎样进行查询数据的封装!

Dish

package com.gch.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.time.LocalDateTime;

/**
 * 菜品表
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Dish {
    /** 主键ID */
    private Integer id;
    /** 菜品名称 */
    private String name;
    /** 菜品分类ID */
    private Integer categoryId;
    /** 菜品图片 */
    private String image;
    /** 描述信息 */
    private String description;
    /** 状态:0停售,1起售 */
    private Short status;
    /** 创建时间 */
    private LocalDateTime createTime;
    /** 更新时间 */
    private LocalDateTime updateTime;

    /** 记录当前菜品所属的分类信息 */
    private Category category;
}

Category

package com.gch.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.time.LocalDateTime;

/**
 * 分类表
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Category {
    /** 主键ID */
    private Integer id;
    /** 分类名称 */
    private String name;
    /** 类型 1-菜品分类 2-套餐分类*/
    private Short type;
    /** 顺序 */
    private Integer sort;
    /** 状态 0-禁用 1-启用 */
    private Short status;
    /** 创建时间 */
    private LocalDateTime createTime;
    /** 更新时间 */
    private LocalDateTime updateTime;
}

DishMapper 

package com.gch.mapper;

import com.gch.pojo.Dish;
import org.apache.ibatis.annotations.Mapper;

import java.util.List;

@Mapper
public interface DishMapper {
    /**
     * 查询菜品,同时查询出该菜品所属的分类
     * @return 将查询出来的多条结果封装到List集合当中
     */
    public List findAllDishWithCategory();
}

DishMapper.xml




    
    

注意:记得在配置文件当中来更新数据库的连接 

MyBatis多表查询_第4张图片

测试类:

    @Autowired
    private DishMapper dishMapper;

    @Test
    public void testFindAllDishWithCategory() {
        List dishList = dishMapper.findAllDishWithCategory();
        dishList.forEach(s ->{
            System.out.println(s);
        });
    }

运行测试方法,看控制台输出:

MyBatis多表查询_第5张图片可以看到catrgory为null,说明查询出来的菜品所属的分类信息没有被正确封装! 

为什么category为null呢?

  • 原因就在于最后是把查询出来的结果封装到Dish对象当中,但是Dish对象当中的属性名就是category,与数据库当中Category表中的字段名完全不一致,因此封装不上。 

2.1 一对一多表查询方式一:基于标签进行手动结果映射封装 

  • 既然默认的规则{实体类类名与表中字段名相同}不能给我们自动封装上,那我们就需要手动封装! 
  • 这里要用到一个标签 - ,Map是映射的意思,resultMap - 结果映射!

MyBatis多表查询_第6张图片




    
    
        
        
        
        
        
        
        
        
        
        

        
        
        
        
        
        
        
    
    
    

再次运行测试方法,看控制台查询结果,已经成功封装! 

MyBatis多表查询_第7张图片MyBatis多表查询_第8张图片注意:

  • 由于上述字段符合规则,因此也可以删掉名,但是为了可读性,因此我们没有删除。
  • 还有下面爆红的字段,这是IDEA的误报。

MyBatis多表查询_第9张图片 

MyBatis多表查询_第10张图片 

2.2 一对一多表查询方式二 - 通过标签来封装属性中所关联的对象

MyBatis多表查询_第11张图片





    
    
    
        
        
        
        
        
        
        
        
        
        

        
        
        
        
        
        
        
    

    
    
        
        
        
        
        
        
        
        
        
        
        
        
            
            
            
            
            
            
            
        
    

    
    

运行测试方法,验证结果是否正确:

MyBatis多表查询_第12张图片

如果在写属性的全类名时,想省略前面的包名不写,那么就可以开启MyBatis的实体类别名配置: 

#MyBatis配置(关键字camel、log-impl)
mybatis:
  configuration:
    #开启MyBatis的日志输出{配置MyBatis的日志,指定输出到控制台}
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
    #开启数据库表字段 到 实体类属性的驼峰映射 a_column ---> aColumn
    map-underscore-to-camel-case: true
  #开启MyBatis的实体类别名配置,相当于如果要写该包下类的全类名,直接写类名即可,前面的包名可以省略
  #别名就是类名的简写,并且首字母不区分大小写
  type-aliases-package: com.gch.pojo

3. 一对多查询

MyBatis多表查询_第13张图片MyBatis多表查询_第14张图片

SQL语句: 

-- 查询所有分类,同时查询出该分类下的菜品数据
select category.*,
       dish.id          as 主键ID,
       dish.name        as 菜品名称,
       dish.category_id as 菜品分类ID,
       dish.price       as 菜品价格,
       dish.image       as 菜品图片,
       dish.description as 描述信息,
       dish.status      as 状态,
       dish.create_time as 创建时间,
       dish.update_time as 更新时间
from category
         left outer join dish on category.id = dish.category_id;

Category 

package com.gch.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

/**
 * 分类表
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Category {
    /** 主键ID */
    private Integer id;
    /** 分类名称 */
    private String name;
    /** 类型 1-菜品分类 2-套餐分类*/
    private Short type;
    /** 顺序 */
    private Integer sort;
    /** 状态 0-禁用 1-启用 */
    private Short status;
    /** 创建时间 */
    private LocalDateTime createTime;
    /** 更新时间 */
    private LocalDateTime updateTime;

    /** 一个分类对应多个菜品,记录该分类下的菜品集合 */
    private List dishList = new ArrayList<>();
}

细节:如果定义集合,一般需要初始化一下,防止拿到的结果为null。 

Dish 

package com.gch.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.time.LocalDateTime;

/**
 * 菜品表
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Dish {
    /** 主键ID */
    private Integer id;
    /** 菜品名称 */
    private String name;
    /** 菜品分类ID */
    private Integer categoryId;
    /** 菜品图片 */
    private String image;
    /** 描述信息 */
    private String description;
    /** 状态:0停售,1起售 */
    private Short status;
    /** 创建时间 */
    private LocalDateTime createTime;
    /** 更新时间 */
    private LocalDateTime updateTime;

    /** 记录当前菜品所属的分类信息 */
    private Category category;
}

CategoryMapper

package com.gch.mapper;

import com.gch.pojo.Category;
import org.apache.ibatis.annotations.Mapper;

import java.util.List;

@Mapper
public interface CategoryMapper {
    /**
     * 查询所有分类,同时查询出该分类下的菜品数据
     * @return
     */
    public List findAllCategoryWithDish();
}

CategoryMapper.xml





    
    
        
        
        
        
        
        
        
        
        
        
            
            
            
            
            
            
            
            
        
    

    
    

测试方法:

    @Autowired
    private CategoryMapper categoryMapper;

    @Test
    public void testFindAllCategoryWithDish(){
        List categoryList = categoryMapper.findAllCategoryWithDish();
        categoryList.forEach(s ->{
            System.out.println(s);
        });
    }

运行测试方法,查看控制台输出结果:

MyBatis多表查询_第15张图片 

4. 多对多查询

MyBatis多表查询_第16张图片学生表、课程表、学生课程关系表。

注意:学生课程这张中间关系表它不是业务表! 

MyBatis多表查询_第17张图片

--  ======================================多对多=============================
create table tb_student(
    id int auto_increment primary key comment '主键ID',
    name varchar(10) comment '姓名',
    no varchar(10) comment '学号'
) comment '学生表';
insert into tb_student(name, no) values ('黛绮丝', '2000100101'),('谢逊', '2000100102'),('殷天正', '2000100103'),('韦一笑', '2000100104');


create table tb_course(
   id int auto_increment primary key comment '主键ID',
   name varchar(10) comment '课程名称'
) comment '课程表';
insert into tb_course (name) values ('Java'), ('PHP'), ('MySQL') , ('Hadoop');


create table tb_student_course(
   id int auto_increment comment '主键' primary key,
   student_id int not null comment '学生ID',
   course_id  int not null comment '课程ID',
   constraint fk_courseid foreign key (course_id) references tb_course (id),
   constraint fk_studentid foreign key (student_id) references tb_student (id)
)comment '学生课程中间表';

insert into tb_student_course(student_id, course_id) values (1,1),(1,2),(1,3),(2,2),(2,3),(3,4);

MyBatis多表查询_第18张图片

MyBatis多表查询_第19张图片 

SQL 

-- 查询所有学生,同时查询出该学生选修的所有课程
select tb_student.*, tc.id as 主键ID, tc.name as 课程名称
from tb_student
         left outer join tb_student_course as tsc on tb_student.id = tsc.student_id
         left outer join tb_course as tc on tsc.course_id = tc.id;

细节:用到了两次左连接! 

Student 

package com.gch.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.ArrayList;
import java.util.List;

/**
   学生表
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student {
    /** 主键ID */
    private Integer id;
    /** 姓名 */
    private String name;
    /** 学号 */
    private String no;

    /** 定义集合,记录该学生选修的所有课程 */
    public List courseList = new ArrayList<>();
}

Course 

package com.gch.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
   课程表
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Course {
    /** 主键ID */
    private Integer id;
    /** 课程名称 */
    private String name;
}

StudentMapper

package com.gch.mapper;

import com.gch.pojo.Student;
import org.apache.ibatis.annotations.Mapper;

import java.util.List;

@Mapper
public interface StudentMapper {
    /**
     * 查询所有学生,同时查询出该学生选修的所有课程
     * @return
     */
    public List findAllStudentWithCourse();
}

StudentMapper.xml 





    
    
        
        
        
        
        
            
            
         
    

    
    

编写测试方法,运行测试方法:

    @Autowired
    private StudentMapper studentMapper;

    @Test
    public void testFindAllStudentWithCourse(){
        List studentList = studentMapper.findAllStudentWithCourse();
        studentList.forEach(s ->{
            System.out.println(s);
        });
    }

MyBatis多表查询_第20张图片 

你可能感兴趣的:(MyBatis,数据库)