java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > mybatis-plus多表联查实现注解方式

mybatis-plus多表联查怎么实现?注解方式查询学生所选课程

作者:会飞的种花家

还在为mybatis-plus多表联查发愁?本文通过学生选课实例,手把手教你使用@Results、@Many等注解实现多表查询,轻松获取学生课程列表,告别繁琐xml配置,快速提升开发效率

前言

查阅了mybatis-plus官方文档,发现对多表联查的说明只言片语,也没有例子,只能自己琢磨琢磨如何利用mybatis-plus进行多表联查了。

使用xml的方式过于冗余,所以在查看了注解的使用后,果断选择利用注解实现。

注解学习

实践出真知,不多说了,直接通过实例来学习吧!

需要解决问题

需要查询这个学生所选的所有课程,查询结果为: 

学生id,学生name,课程Course对象的list集合

和查询这个教师所教的所有课程,查询结果为: 

教师id,教师name,课程Course对象的list集合

上述问题实际上是一致的,可通过解决其一然后通过C+V解决

下面我们就学生来解决。

实际呢,学生类Student只有两个属性,那就是 

我们需要通过二者的关系表查询出我们想要的Course对象的list集合

这个关系表为Takes,也为Takes类。

其属性有 

id,studentId,courseId(数据库与其一致)

问题描述完毕,下面我们开始实践。

数据库部分

学生表

-- ----------------------------
-- Table structure for student
-- ----------------------------
DROP TABLE IF EXISTS `student`;
CREATE TABLE `student` (
  `id` int NOT NULL,
  `name` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
  PRIMARY KEY (`id`),
  KEY `name` (`name`),
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
-- ----------------------------
-- Records of student
-- ----------------------------
INSERT INTO `student` VALUES ('18120107', '学生九');
INSERT INTO `student` VALUES ('18120108', '学生十号');
INSERT INTO `student` VALUES ('18120101', '张三');
INSERT INTO `student` VALUES ('18120102', '李四');
INSERT INTO `student` VALUES ('18120103', '王五');
INSERT INTO `student` VALUES ('18120105', '田七');
INSERT INTO `student` VALUES ('18120104', '赵六');
INSERT INTO `student` VALUES ('18120106', '陈八');

课程表

-- ----------------------------
-- Table structure for course
-- ----------------------------
DROP TABLE IF EXISTS `course`;
CREATE TABLE `course` (
  `id` int NOT NULL,
  `name` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
  PRIMARY KEY (`id`),
  KEY `name` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
-- ----------------------------
-- Records of course
-- ----------------------------
INSERT INTO `course` VALUES ('87508', 'JavaWeb开发');
INSERT INTO `course` VALUES ('87502', '操作系统');
INSERT INTO `course` VALUES ('87505', '数据库原理');
INSERT INTO `course` VALUES ('87501', '数据结构');
INSERT INTO `course` VALUES ('87506', '算法设计与分析');
INSERT INTO `course` VALUES ('87504', '计算机组成');
INSERT INTO `course` VALUES ('87503', '计算机网络');
INSERT INTO `course` VALUES ('87509', '软件协同设计');
INSERT INTO `course` VALUES ('87507', '软件工程');

选课表

(这里的course_name属性其实是多余的,暂且留着)

-- ----------------------------
-- Table structure for takes
-- ----------------------------
DROP TABLE IF EXISTS `takes`;
CREATE TABLE `takes` (
  `id` int NOT NULL AUTO_INCREMENT,
  `student_id` int NOT NULL,
  `course_id` int NOT NULL,
  `course_name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
  PRIMARY KEY (`id`),
  KEY `fk_takes_student_id` (`student_id`),
  KEY `fk_takes_course_id` (`course_id`),
  KEY `fk_takes_course_name` (`course_name`),
  CONSTRAINT `fk_takes_course_id` FOREIGN KEY (`course_id`) REFERENCES `course` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
  CONSTRAINT `fk_takes_course_name` FOREIGN KEY (`course_name`) REFERENCES `course` (`name`) ON DELETE CASCADE ON UPDATE CASCADE,
  CONSTRAINT `fk_takes_student_id` FOREIGN KEY (`student_id`) REFERENCES `student` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=25 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
-- ----------------------------
-- Records of takes
-- ----------------------------
INSERT INTO `takes` VALUES ('1', '18120101', '87501', '数据结构');
INSERT INTO `takes` VALUES ('2', '18120101', '87502', '操作系统');
INSERT INTO `takes` VALUES ('3', '18120101', '87503', '计算机网络');
INSERT INTO `takes` VALUES ('4', '18120102', '87501', '数据结构');
INSERT INTO `takes` VALUES ('5', '18120102', '87502', '操作系统');
INSERT INTO `takes` VALUES ('6', '18120102', '87503', '计算机网络');
INSERT INTO `takes` VALUES ('7', '18120103', '87509', '软件协同设计');
INSERT INTO `takes` VALUES ('8', '18120103', '87508', 'JavaWeb开发');
INSERT INTO `takes` VALUES ('9', '18120103', '87507', '软件工程');
INSERT INTO `takes` VALUES ('10', '18120104', '87503', '计算机网络');
INSERT INTO `takes` VALUES ('11', '18120104', '87506', '算法设计与分析');
INSERT INTO `takes` VALUES ('12', '18120104', '87507', '软件工程');
INSERT INTO `takes` VALUES ('13', '18120105', '87502', '操作系统');
INSERT INTO `takes` VALUES ('14', '18120105', '87504', '计算机组成');
INSERT INTO `takes` VALUES ('15', '18120105', '87505', '数据库原理');
INSERT INTO `takes` VALUES ('16', '18120106', '87501', '数据结构');
INSERT INTO `takes` VALUES ('17', '18120106', '87503', '计算机网络');
INSERT INTO `takes` VALUES ('18', '18120106', '87505', '数据库原理');
INSERT INTO `takes` VALUES ('19', '18120107', '87509', '软件协同设计');
INSERT INTO `takes` VALUES ('20', '18120107', '87506', '算法设计与分析');
INSERT INTO `takes` VALUES ('21', '18120107', '87504', '计算机组成');
INSERT INTO `takes` VALUES ('22', '18120108', '87506', '算法设计与分析');
INSERT INTO `takes` VALUES ('23', '18120108', '87507', '软件工程');
INSERT INTO `takes` VALUES ('24', '18120108', '87508', 'JavaWeb开发');

实体类

用了lombok插件自动生成相关方法,getter,setter,构造器等

学生类

这里解释一下,List《Course》上方这**个@TableField(exist = false)**注解表示该属性不为数据库中的字段(其实是为了图方便直接写到了实体类里面,实际开发应该多写一个Vo类继承自Student而后再写这一个属性)

@Data
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(callSuper = false)
public class Student implements Serializable {

	private static final long serialVersionUID = 1L;

	@TableId(value = "id", type = IdType.NONE)
	private Integer id;

	private String name;

	@TableField(exist = false)
	private List<Course> courses;
	
}

课程类

@Data
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(callSuper = false)
public class Course implements Serializable {

	private static final long serialVersionUID = 1L;

	@TableId(value = "id", type = IdType.NONE)
	private Integer id;

	private String name;


}

选课类

还是一样,这个courseName可以忽略,实际是不需要的

@Data
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(callSuper = false)
public class Takes implements Serializable {

	private static final long serialVersionUID = 1L;

	@TableId(value = "id", type = IdType.AUTO)
	private Integer id;

	private int studentId;

	private int courseId;

	private String courseName;

}

重点来了!

Mapper层

CourseMapper

这里明显能看明白,就是查出这个学生的所有课程,返回一个课程列表

public interface CourseMapper extends BaseMapper<Course> {


    @Select("select * from course where id in(select course_id from takes where student_id=#{stuId})")
    List<Course> queryCoursesByStuId(Integer stuId);

}

StudentMapper

全文就这里是最关键的了

首先,外部查询出这个学生对象,在@Results注解内,表示返回的实际结果集,

前面两个@Result,就是学生id和name了,这里不用说

主要是第三个@Result,通过javaType=List.class,many=@Many来指定这个Result的属性(通过CourseMapper中的方法来查询这个list集合)注意:要写方法名的全名称,包名+类名+方法名

@Select("select * from student where id=#{id}")
    @Results({
            @Result(column="id",property="id",id=true),
            @Result(column = "name",property = "name"),
            @Result(column="id",property="courses",javaType= List.class,
                    many=@Many(
                            select="com.usst.mapper.CourseMapper.queryCoursesByStuId"
                    )
            )
    })
    Student queryStuById(@Param("id") Integer id);

其实写到这里,Service层不言而喻就出来了,不过还是再写一下吧

Service层

StudentService

public interface StudentService extends IService<Student> {
	Student queryStuById(@Param("id") int id);
}

StudentServiceImpl

@Service
public class StudentServiceImpl extends ServiceImpl<StudentMapper, Student> implements StudentService {

	@Autowired
	private StudentMapper studentMapper;

	@Override
	public Student queryStuById(int id) {
		return this.studentMapper.queryStuById(id);
	}
}

结果测试

    @Autowired
    private StudentService studentService;
    @Test
    void test(){
        System.out.println(studentService.queryStuById(18120101).toString());
    }

测试结果截图:

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

您可能感兴趣的文章:
阅读全文