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 */;
一对多,多对一用的是同样的两张表,实体类就发一次
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(); }
这里看完之后,就有我说的自关联和多对多都与一对多有点相似的味道
本章完