目录
1. 多表关系回顾
2. 一对一查询
2.1 一对一多表查询方式一:基于标签进行手动结果映射封装
2.2 一对一多表查询方式二 - 通过标签来封装属性中所关联的对象
3. 一对多查询
4. 多对多查询
一张表对应一个实体类,一个实体类对应一个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
注意:记得在配置文件当中来更新数据库的连接
测试类:
@Autowired
private DishMapper dishMapper;
@Test
public void testFindAllDishWithCategory() {
List dishList = dishMapper.findAllDishWithCategory();
dishList.forEach(s ->{
System.out.println(s);
});
}
运行测试方法,看控制台输出:
可以看到catrgory为null,说明查询出来的菜品所属的分类信息没有被正确封装!
为什么category为null呢?
再次运行测试方法,看控制台查询结果,已经成功封装!
运行测试方法,验证结果是否正确:
如果在写属性的全类名时,想省略前面的包名不写,那么就可以开启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
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);
});
}
运行测试方法,查看控制台输出结果:
注意:学生课程这张中间关系表它不是业务表!
-- ======================================多对多=============================
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);
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);
});
}