mybatis-嵌套查询模式设计|数据库设计|

案例数据库介绍

  • 最近学习了ssm框架,所以准备把之前用原生Servlet做的一个小项目,改成ssm框架形式。没想到带来了这么多问题,但是解决后还是学到了很多东西,这是根据我自己的理解记录的一篇白话博文。
  • 这个案例中,表与表之间的关系是很典型的稍微复杂一点点的多对多关系。一个选课系统
  • 我的数据库设计是这样的:学生选课时,选择的其实选的是教师和课程绑定的关系。三个实体课程、学生、教师两两之间都是多对多关系。废话不多说直接上图,直接明了。
    mybatis-嵌套查询模式设计|数据库设计|_第1张图片

未改进代码

在没有学习mybatis框架前,我们如果要查询表与表的关系时多对多的情况时,只能采取连接查询,这样就是的我们的sql语句特别复杂,看起来很难受,而且在写这种sql语句时,也是一种挑战,尤其是当多对多关系复杂时,我的这个小案例就是这样。
mybatis让我们只关心sql语句,简化了开发。尤其是他可以使用嵌套查询,让我们不用再去使用复杂的连接查询语句,这样其实不仅简化了sql语句,而且也降低了耦合,让sql语句有有了很多的调用机会。
没有改进前
学生类、教师类和课程类

public class Student {
    private Integer sid;//学生编号
    private String snum;//学号
    private String sname;//学生姓名
    private String spassword;// 密码
    private String syear;//年级
    private String smajor;//专业
    private String sdept;//院系

public class Course {
    private Integer cid;//课程代码
    private String cname;//课程名
    private String ctype;//课程性质
    private Integer ccredit;//学分
    private Integer ctime;//学时
    
public class Teacher {
    private Integer tid;// 教师编号
    private String tnum;//教师号
    private String tname;//教师姓名
    private String tpassword;//密码
    private String tdept;//院系
    
//get/set、toString方法省略

选课类(这是改进前分析的实体类截图,改进后这个类就不存在了)
mybatis-嵌套查询模式设计|数据库设计|_第2张图片
教师课程绑定关系类

public class TeacherAndCourse {
    private Integer tcid;//授课代码
    private String tcplace;//上课地点
    private String tctime;//上课时间
    private String tcgrade;//学年

    private List<Teacher> teacherList;//授课教师
    private List<Course> courseList;//授课课程
    
	//get/set、toString方法省略

这是查询学生选课情况的各个Dao之间的调用关系:
mybatis-嵌套查询模式设计|数据库设计|_第3张图片
这样是可以查出数据的,但是数据是有问题的。

  1. 由于实体类的设计,使得查出来的数据很难在页面上显示,因为由上图我们知道最终返回给页面的是一个List< Curricula > ,Curricula中有List< TeacherAndCourse > 和List< Studnet > ,在TeacherAndCourse 类中还有List< Course >和List< Teacher > 。页面真的很难去显示这些数据。
  2. 由于这种Dao层的设计,让嵌套查询了多次,使得查到的数据冗余重复。
    我这里根据数据库得到的是三条相同的数据,因为已经改进,所以数据只有截图,用不同颜色表示了三段数据,马赛克是姓名。
    mybatis-嵌套查询模式设计|数据库设计|_第4张图片

两个成功的案例

发现问题后,我回顾了一下课程里老师写过的两个案例。让我受益匪浅,开始按照这种方式做。

订单案例

mybatis-嵌套查询模式设计|数据库设计|_第5张图片

权限、角色、用户案例

mybatis-嵌套查询模式设计|数据库设计|_第6张图片

改进后的代码

开始改进代码。

实体类改进

删除选课类Curricula ,
给Student类添加 private List teacherAndCourseList;属性,
给Teacher类添加private List courseList;属性
给Course类添加private List teacherList;属性

public class Student {
    private Integer sid;//学生编号
    private String snum;//学号
    private String sname;//学生姓名
    private String spassword;// 密码
    private String syear;//年级
    private String smajor;//专业
    private String sdept;//院系

    private List<TeacherAndCourse> teacherAndCourseList;
public class TeacherAndCourse {
    private Integer tcid;//授课代码
    private String tcplace;//上课地点
    private String tctime;//上课时间
    private String tcgrade;//学年

    private List<Teacher> teacherList;//授课教师
    private List<Course> courseList;//授课课程


public class Teacher {
    private Integer tid;// 教师编号
    private String tnum;//教师号
    private String tname;//教师姓名
    private String tpassword;//密码
    private String tdept;//院系

    private List<Course> courseList;

public class Course {
    private Integer cid;//课程代码
    private String cname;//课程名
    private String ctype;//课程性质
    private Integer ccredit;//学分
    private Integer ctime;//学时

    private List<Teacher> teacherList;

Dao层改进

StudentDao#findBySid(String “学生id”):

/**
* 通过学号查询选课记录
*
* @return
*/
@Select("SELECT * FROM t_stu WHERE sid=#{sid}")
@Results({
       @Result(property = "oid",column = "oid"),
       @Result(property = "snum",column = "snum"),
       @Result(property = "sname",column = "sname"),
       @Result(property = "spassword",column = "spassword"),
       @Result(property = "syear",column = "syear"),
       @Result(property = "smajor",column = "smajor"),
       @Result(property = "sdept",column = "sdept"),

       @Result(property = "teacherAndCourseList",column = "sid",javaType = java.util.List.class,
               many = @Many(select = "com.bjwlxy.choosecourse.dao.TeacherAndCourseDao.findBySid",fetchType = FetchType.EAGER))
})
public Student findBySid(String sid);

TeacherAndCourseDao#findBySid(String “学生id”):
注意这里的"select * from t_tc where tcid in (select tcid from t_option where sid=#{sid})",是通过sql去查tcid。

@Select("select * from t_tc where tcid in (select tcid from t_option where sid=#{sid})")
@Results({
        @Result(id = true,property = "tcid",column = "tcid"),
        @Result(property = "tcplace",column = "tcplace"),
        @Result(property = "tctime",column = "tctime"),
        @Result(property = "tcgrade",column = "tcgrade"),
        @Result(property = "teacherList",column = "tid",javaType = java.util.List.class,
                many = @Many(select = "com.bjwlxy.choosecourse.dao.TeacherDao.findById",fetchType = FetchType.EAGER)),
        @Result(property = "courseList",column = "cid",javaType = java.util.List.class,
                many = @Many(select = "com.bjwlxy.choosecourse.dao.CourseDao.findById",fetchType = FetchType.EAGER)),
})
public List<TeacherAndCourse> findBySid(Integer sid);

TeacherDao#findById(String “教师id”)

@Select("select * from t_teacher where tid=#{tid}")
public List<Teacher> findById(Integer tid);

CourseDao#findById(String “课程id”)

@Select("select * from t_course where cid=#{cid}")
public List<Course> findById(Integer cid);

这样得到的数据是比较合理,也比较方便展示的。
在这里插入图片描述
分析一下数据:

  1. 现在由于domain层中的设计,得到的就是一个学生对象,而学生对象中包含了选课信息。这是比较合理的。
  2. Dao层的设计,使得方法重用性变高了,
Student{
  sid=null, snum='201796084111', sname='xxxx', spassword='123456', syear='2017', smajor='软件工程', sdept='计算机学院',
   teacherAndCourseList=
       [TeacherAndCourse
           {tcid=1, tcplace='石鼓校区综合楼605', tctime='周二4,5节,周四1,2节', tcgrade='2019-2020',
           teacherList=[Teacher{tid=2, tnum='1022', tname='xxxx', tpassword='123456', tdept='计算机学院',
           courseList=null}], courseList=[Course{cid=1, cname='计算机原理', ctype='专业核心课', ccredit=2, ctime=18, teacherList=null}]},
       TeacherAndCourse
           {tcid=2, tcplace='石鼓校区综合楼605', tctime='周二4,5节,周五4,5节', tcgrade='2019-2020',
           teacherList=[Teacher{tid=1, tnum='1021', tname='xxxx', tpassword='123456', tdept='计算机学院',
           courseList=null}], courseList=[Course{cid=1, cname='计算机原理', ctype='专业核心课', ccredit=2, ctime=18, teacherList=null}]},
       TeacherAndCourse
           {tcid=3, tcplace='石鼓校区综合楼605', tctime='周三5,6节,周四1,2节', tcgrade='2019-2020',
           teacherList=[Teacher{tid=1, tnum='1021', tname='xxxx', tpassword='123456', tdept='计算机学院',
           courseList=null}],courseList=[Course{cid=2, cname='java程序设计', ctype='专业核心课', ccredit=2, ctime=16, teacherList=null}]}]}

你可能感兴趣的:(ssm_)