SSM-MyBatis-15:Mybatis中关联查询(多表操作)

 

 

------------吾亦无他,唯手熟尔,谦卑若愚,好学若饥-------------

 

 

先简单提及一下关联查询的分类

  1.一对多

    1.1单条SQL操作的

    1.2多条SQL操作的

  2.多对一

    2.1单条SQL操作的

    2.1多条SQL操作的

  3.多对多(类似一对多)

  4.自关联(也有点类似一对多)

下面是具体实现,用真实代码带入进去(数据表和实体类和测试方法都给发出来,更多的要关注到xml中的使用)

  我先把用到的数据库的脚本发一下,里面有测试数据,我折起来,需要使用的可以自行提取

/*
SQLyog v10.2 
MySQL - 5.6.24 : Database - s2228
*********************************************************************
*/


/*!40101 SET NAMES utf8 */;

/*!40101 SET SQL_MODE=''*/;

/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
CREATE DATABASE /*!32312 IF NOT EXISTS*/`s2228` /*!40100 DEFAULT CHARACTER SET utf8 */;

USE `s2228`;

/*Table structure for table `book` */

DROP TABLE IF EXISTS `book`;

CREATE TABLE `book` (
  `bookID` int(11) NOT NULL AUTO_INCREMENT,
  `bookName` varchar(32) DEFAULT NULL,
  `bookAuthor` varchar(32) DEFAULT NULL,
  `bookPrice` int(11) DEFAULT NULL,
  PRIMARY KEY (`bookID`)
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8;

/*Data for the table `book` */

insert  into `book`(`bookID`,`bookName`,`bookAuthor`,`bookPrice`) values (1,'程序员的人生','老原教育',500),(2,'皮的修养','郭彦',999),(3,'如何成为一代大牛','迟总',500),(4,'心想事成','孟六',999),(5,'心想事成','孟六',999),(6,'心想事成','孟七',999),(7,'心想事成','孟七',999),(8,'心想事成','孟七',999);

/*Table structure for table `category` */

DROP TABLE IF EXISTS `category`;

CREATE TABLE `category` (
  `cid` int(11) NOT NULL AUTO_INCREMENT,
  `cname` varchar(32) DEFAULT NULL,
  `pid` int(11) NOT NULL,
  PRIMARY KEY (`cid`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;

/*Data for the table `category` */

insert  into `category`(`cid`,`cname`,`pid`) values (1,'图书',0),(2,'青年图书',1),(3,'少儿图书',1),(4,'我爱科学',3),(5,'服装',0),(6,'羽绒服',5);

/*Table structure for table `dept` */

DROP TABLE IF EXISTS `dept`;

CREATE TABLE `dept` (
  `deptNo` int(8) NOT NULL AUTO_INCREMENT,
  `deptName` varchar(32) DEFAULT NULL,
  PRIMARY KEY (`deptNo`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;

/*Data for the table `dept` */

insert  into `dept`(`deptNo`,`deptName`) values (1,'开发部');

/*Table structure for table `emp` */

DROP TABLE IF EXISTS `emp`;

CREATE TABLE `emp` (
  `empNo` int(8) NOT NULL AUTO_INCREMENT,
  `empName` varchar(32) DEFAULT NULL,
  `deptNo` int(8) NOT NULL,
  PRIMARY KEY (`empNo`),
  KEY `emp_deptNo_Fk_dept_deptNo_pk` (`deptNo`),
  CONSTRAINT `emp_deptNo_Fk_dept_deptNo_pk` FOREIGN KEY (`deptNo`) REFERENCES `dept` (`deptNo`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;

/*Data for the table `emp` */

insert  into `emp`(`empNo`,`empName`,`deptNo`) values (1,'孟六',1),(2,'孟六',1);

/*Table structure for table `student` */

DROP TABLE IF EXISTS `student`;

CREATE TABLE `student` (
  `sid` int(11) NOT NULL AUTO_INCREMENT,
  `sname` varchar(32) NOT NULL,
  PRIMARY KEY (`sid`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;

/*Data for the table `student` */

insert  into `student`(`sid`,`sname`) values (1,'孟六'),(2,'王五'),(3,'赵七'),(4,'郭皮');

/*Table structure for table `teacher` */

DROP TABLE IF EXISTS `teacher`;

CREATE TABLE `teacher` (
  `tid` int(11) NOT NULL AUTO_INCREMENT,
  `tname` varchar(32) NOT NULL,
  PRIMARY KEY (`tid`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;

/*Data for the table `teacher` */

insert  into `teacher`(`tid`,`tname`) values (1,'迟老师'),(2,'原老师'),(3,'付老师'),(4,'超哥');

/*Table structure for table `teacher_student` */

DROP TABLE IF EXISTS `teacher_student`;

CREATE TABLE `teacher_student` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `tid` int(11) NOT NULL,
  `sid` int(11) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;

/*Data for the table `teacher_student` */

insert  into `teacher_student`(`id`,`tid`,`sid`) values (1,1,1),(2,1,3),(3,2,1),(4,4,1);

/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
数据库sql脚本

  一对多,多对一用的是同样的两张表,实体类就发一次

  1.一对多(单条多条操作一块发出来,对应上看即可)

    实体类

//第一个实体类
package cn.dawn.demo03.entity;

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

/**
 * Created by Dawn on 2018/2/26.
 */
public class Dept {
    private Integer deptNo;
    private String deptName;
    private List<Emp> emps=new ArrayList<Emp>();

    public Integer getDeptNo() {
        return deptNo;
    }

    public void setDeptNo(Integer deptNo) {
        this.deptNo = deptNo;
    }

    public String getDeptName() {
        return deptName;
    }

    public void setDeptName(String deptName) {
        this.deptName = deptName;
    }

    public List<Emp> getEmps() {
        return emps;
    }

    public void setEmps(List<Emp> emps) {
        this.emps = emps;
    }
}
//第二个实体类
package cn.dawn.demo03.entity;

/**
 * Created by Dawn on 2018/2/26.
 */
public class Emp {
    private Integer empNo;
    private String empName;
    private Integer deptNo;
    private Dept dept;

    public Dept getDept() {
        return dept;
    }

    public void setDept(Dept dept) {
        this.dept = dept;
    }

    public Integer getEmpNo() {
        return empNo;
    }

    public void setEmpNo(Integer empNo) {
        this.empNo = empNo;
    }

    public String getEmpName() {
        return empName;
    }

    public void setEmpName(String empName) {
        this.empName = empName;
    }

    public Integer getDeptNo() {
        return deptNo;
    }

    public void setDeptNo(Integer deptNo) {
        this.deptNo = deptNo;
    }
}

    接口中的方法

    /*一对多单挑sql*/
    public Dept findDeptnoALLEmps(Integer deptNo);
    /*一对多多条sql*/
    public Dept findDeptnoALLEmpsMoreSql(Integer deptNo);

 

    接口同名的xml文件中

<!--一对多单条sql-->
    <resultMap id="DeptMapper" type="Dept">
        <id column="deptNo" property="deptNo"></id>
        <result column="deptName" property="deptName"></result>
        <collection property="emps" ofType="Emp">
            <id column="empNo" property="empNo"></id>
            <result column="empName" property="empName"></result>
        </collection>
    </resultMap>
    <!--一对多多条sql-->
    <resultMap id="DeptMoreSqlMapper" type="Dept">
        <id column="deptNo" property="deptNo"></id>
        <result column="deptName" property="deptName"></result>
        <collection property="emps" ofType="Emp" select="findDeptnoALLEmpsMoreSqlEmps" column="deptNo">
            <id column="empNo" property="empNo"></id>
            <result column="empName" property="empName"></result>
        </collection>
    </resultMap>
    <!--一对多单条sql-->
    <select id="findDeptnoALLEmps" resultMap="DeptMapper">
        SELECT d.deptNo,empNo,deptName,empName FROM dept d,emp e WHERE d.deptNo=e.DeptNo AND d.deptNo=#{deptNo}
    </select>
    <!--一对多多条sql-->
    <select id="findDeptnoALLEmpsMoreSql" resultMap="DeptMoreSqlMapper">
        SELECT deptNo,deptName FROM dept WHERE deptNo=#{deptNo}
    </select>
    <select id="findDeptnoALLEmpsMoreSqlEmps" resultType="Emp">
        SELECT * FROM emp where deptNo=#{deptNo}
    </select>

    测试方法

    /*一对多多条sql*/
    @Test
    public void t2OnePkMoreMoreSQL(){
        SqlSession session= MyBatisUtils.getSession();

        IDeptDAO mapper = session.getMapper(IDeptDAO.class);
        Dept depts = mapper.findDeptnoALLEmpsMoreSql(1);
        System.out.println(depts.getDeptName()+"================"+depts.getDeptNo());
        for (Emp item:depts.getEmps()) {
            System.out.println(item.getEmpName());
        }


        session.close();

    }

    /*一对多单条sql*/
    @Test
    public void t1OnePkMoreOneSQL(){
        SqlSession session= MyBatisUtils.getSession();

        IDeptDAO mapper = session.getMapper(IDeptDAO.class);
        Dept depts = mapper.findDeptnoALLEmps(1);
        System.out.println(depts.getDeptName()+"================"+depts.getDeptNo());
        for (Emp item:depts.getEmps()) {
            System.out.println(item.getEmpName());
        }


        session.close();

    }

  2.多对一

    接口中的方法

    /*多对一单挑sql*/
    public Emp findempnoALLDept(Integer empNo);
    /*多对一多条sql*/
    public Emp findempnoALLDeptMoreSQL(Integer empNo);

    同名xml中的Mapper中的内容

    <!--多对一单条sql-->
    <resultMap id="EmpMapper" type="Emp">
        <id column="empNo" property="empNo"></id>
        <result column="empName" property="empName"></result>
        <association property="dept" javaType="Dept">
            <result column="deptName" property="deptName"></result>

        </association>
    </resultMap>
    <!--多对一多条sql-->
    <resultMap id="EmpMapperMulti" type="Emp">
        <id column="empNo" property="empNo"></id>
        <result column="empName" property="empName"></result>
        <association property="dept" javaType="Dept" column="deptNo" select="EmpMapperMultiMore">

        </association>
    </resultMap>
    <!--多对一单条sql-->
    <select id="findempnoALLDept" resultMap="EmpMapper">
        SELECT * FROM dept d,emp e WHERE d.deptNo=e.DeptNo AND empNo=#{empNo}
    </select>
    <!--多对一多条sql-->
    <select id="findempnoALLDeptMoreSQL" resultMap="EmpMapperMulti">
        SELECT * FROM emp e WHERE empNo=#{empNo}
    </select>
    <select id="EmpMapperMultiMore" resultType="Dept">
        SELECT * FROM dept WHERE deptNo=#{deptNo}
    </select>

    测试类中的方法

    /*多对一多条sql*/
    @Test
    public void t4MorePkOneMoreSQL(){
        SqlSession session= MyBatisUtils.getSession();

        IEmpDAO mapper = session.getMapper(IEmpDAO.class);
        Emp emp = mapper.findempnoALLDeptMoreSQL(1);
        System.out.println("员工姓名==================="+emp.getEmpName());
        System.out.println("员工部门名称==================="+emp.getDept().getDeptName());



        session.close();

    }


    /*多对一单条sql*/
    @Test
    public void t3MorePkOneOneSQL(){
        SqlSession session= MyBatisUtils.getSession();

        IEmpDAO mapper = session.getMapper(IEmpDAO.class);
        Emp emp = mapper.findempnoALLDept(1);
        System.out.println("员工姓名==================="+emp.getEmpName());
//        System.out.println("员工部门名称==================="+emp.getDept().getDeptName());



        session.close();

    }

  一对多和多对一,他们一个是用ofType,一个是javaType

  3.多对多

    简单解释一下,学生和老师,一个学生可以有多个老师,一个老师可以教多个学生, 怎么表示映射关系,提出了中间表,

    我简单把三张表的脚本再拎出来,看一下,哦,原来是这样

create table Teacher
(
  tid int primary key not null auto_increment,
  tname varchar(32) not null
);

create table Student
(
  sid int primary key not null auto_increment,
  sname varchar(32) not null
);

create table Teacher_Student
(
  id int primary key not null auto_increment,
  tid int not null,
  sid int not null
);

    中间表Teacher_Student有一列流水号主键ID,老师id,学生id,这样一对应,就可以解释清除什么是多对多

    说一下实体类

//第一个学生类
package cn.dawn.demo03.entity;

/**
 * Created by Dawn on 2018/2/26.
 */
public class Student {
    private Integer sid;
    private String sname;

    public Integer getSid() {
        return sid;
    }

    public void setSid(Integer sid) {
        this.sid = sid;
    }

    public String getSname() {
        return sname;
    }

    public void setSname(String sname) {
        this.sname = sname;
    }
}
//第二个老师类
package cn.dawn.demo03.entity;

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

/**
 * Created by Dawn on 2018/2/26.
 */
public class Teacher {
    private Integer tid;
    private String tname;
    //植入学生集合
    private List<Student> stus=new ArrayList<Student>();

    public Integer getTid() {
        return tid;
    }

    public void setTid(Integer tid) {
        this.tid = tid;
    }

    public String getTname() {
        return tname;
    }

    public void setTname(String tname) {
        this.tname = tname;
    }

    public List<Student> getStus() {
        return stus;
    }

    public void setStus(List<Student> stus) {
        this.stus = stus;
    }
}

    下来看接口中的方法,我写的是一个根据传进去的老师ID查看该老师教的所有学生的方法

    /*多对多*/
    /*根据老师id查询他的全部学生*/
    public Teacher findAllStudentsByTid(Integer tid);

    接口同名的xml小配置中的mapper内

    <!--多对多-->
    <resultMap id="TeacherMapper" type="Teacher">
        <id property="tid" column="tid"></id>
        <result column="tname" property="tname"></result>
        <collection property="stus" ofType="Student">
            <id property="sid" column="sid"></id>
            <result column="sname" property="sname"></result>
        </collection>
    </resultMap>
    <!--多对多-->
    <select id="findAllStudentsByTid" resultMap="TeacherMapper">
        SELECT * FROM teacher t,student s,teacher_student ts WHERE t.tid=ts.tid AND s.sid=ts.sid AND t.tid=#{tid}
    </select>

    测试方法

    /*多对多*/
    @Test
    public void t5MorePkMore(){
        SqlSession session= MyBatisUtils.getSession();

        ITeacherDAO mapper = session.getMapper(ITeacherDAO.class);
        Teacher teacher = mapper.findAllStudentsByTid(1);
        System.out.println(teacher.getTname());
        for (Student item:teacher.getStus()) {
            System.out.println(item.getSname());
        }



        session.close();

    }

  4.自关联,自关联是什么啊?就是自己里面有自己的集合,打个比方,衣服---》羽绒服----》男款羽绒服,常见的分类对吧,他们都算作分类,但是还有包含关系,就用到了自关联

    它的思想很棒,笔者第一次见到数据表的时候懵了,但是看到实体类的时候,豁然开朗,哦,原来是这样,我明白了,然后就知道怎么处理了

    (当然,那会是没接触框架的时候,框架还需要更深一点的套路)

    

      由于这儿第一次接触有点难理解,我把表的截图放上来

    

    他的pid为0的时候代表的他的父分类没有,他就是一级分类,他的pid(父id)对应的是别的cid的时候,表示他是此cid的子分类,很拗口,看了实体类就懂了

      实体类

 

package cn.dawn.demo03.entity;

import java.util.Set;

/**
 * Created by Dawn on 2018/2/26.
 */
public class Category {
    private Integer cid;
    private String cname;
    private Set<Category> cates;

    @Override
    public String toString() {
        return "Category{" +
                "cid=" + cid +
                ", cname='" + cname + '\'' +
                ", cates=" + cates +
                '}';
    }

    public Integer getCid() {
        return cid;
    }

    public void setCid(Integer cid) {
        this.cid = cid;
    }

    public String getCname() {
        return cname;
    }

    public void setCname(String cname) {
        this.cname = cname;
    }

    public Set<Category> getCates() {
        return cates;
    }

    public void setCates(Set<Category> cates) {
        this.cates = cates;
    }
}

 

    这儿重写了toString方法,方便展示所有数据

    接口中的方法为

 

    /*自关联*/
    /*根据父id查全部子分类*/
    public List<Category> findAllCategorySetBypid(Integer pid);

 

    接口同名的xml小配置中的mapper中的节点

    <!--自关联-->
    <resultMap id="CategoryMapper" type="Category">
        <id column="cid" property="cid"></id>
        <result property="cname" column="cname"></result>
        <collection property="cates" column="cid" ofType="Category" select="findAllCategorySetBypid"></collection>
    </resultMap>
    <!--多对多-->
    <select id="findAllCategorySetBypid" resultMap="CategoryMapper">
        SELECT * FROM category WHERE pid=#{pid}
    </select>

    测试方法

 

    /*自关联*/
    @Test
    public void t6selfPk(){
        SqlSession session= MyBatisUtils.getSession();

        ICategoryDAO mapper = session.getMapper(ICategoryDAO.class);
        List<Category> lists = mapper.findAllCategorySetBypid(0);
        System.out.println(lists);


        session.close();

    }

 

  这里看完之后,就有我说的自关联和多对多都与一对多有点相似的味道

本章完

posted @ 2018-02-26 19:30  晨曦Dawn  阅读(492)  评论(0编辑  收藏  举报