1、SSM开发实战教程第第3章章 多表关联查询多表关联查询一对多关联查询是指,在查询一方对象的时候,同时将其所关联的多方对象也都查询出来。(1)拷贝项目mybatis22为mybatis31,修改配置文件。其中配置文件如下,注意多了:别名的配置:映射文件的配置:3.1 一对多查询一对多查询(2)修改数据库修改表student,添加一列classno类型varchar(10),可空,该列添加值201801。ALTER TABLE student ADD COLUMN classno VARCHAR(10);UPDATE student SET classno=201801;新建数据表classes并
2、添加数据。create table classes(cid varchar(30),cname varchar(60);insert into classes(cid,cname)values(201801,计算机软件1班);insert into classes(cid,cname)values(201802,计算机软件2班);(3)创建实体类Student和Classes。Student类:public class Student private String sid;private String sname;private String sex;private int age;/所在班级
3、private Classes classes;Classes类:public class Classes private String cid;private String cname;private List students;这种方式只用到1条SQL语句,代码如下所示。select cid,cname,id,studentname,gender,age from classes,student where classes.cid=student.classno and classes.cid=#cid3.1.1 方式一多表连接查询方式方式一多表连接查询方式【注意注意】即使字段名与属性名相
4、同,在中也要写出它们的映射关系。因为框架是依据这个封装对象的。另外,在“一方”的映射文件中使用标签体现出两个实体对象间的关联关系。其两个属性的解释如下:property:指定关联属性,即Class类中的集合属性students。ofType:集合属性的泛型类型,即Student。多表连接查询方式是将多张表进行连接,连为一张表后进行查询。其查询的本质是一张表。而多表单独查询方式是多张表各自查询各自的相关内容,需要多张表的联合数据,再将主表的查询结果联合其它表的查询结果,封装为一个对象。多个查询是可以跨越多个映射文件的,即是可以跨越多个namespace 的。在使用其它namespace的查询时,
5、添加上其所在的 namespace 即可。这种方式要用到2条SQL语句,代码如下所示。3.1.2 方式二多表单独查询方式方式二多表单独查询方式 select*from student where calssno=#cid select cid,cname from classes where cid=#cid 先执行findClassesById查询主表classes,查询出各个列的值,包括cid。查主表出来的各个列值传递给进行结果映射。其中cid 的值还要传给节点作为实参。执行selectStudentsByClasses查询,以cid做为实参,查询出结果,结果封装为。多对一关联查询是指在查
6、询多方对象的时候,同时将其所关联的一方对象也查询出来。由于在查询多方对象时也是一个一个查询,所以多对一关联查询,其实就是一对一关联查询。即一对一关联查询的实现方式与多对一的实现方式是相同的。配置多对一关联的重点在于“多方”的映射文件要有属性关联“一方”。3.2 多对一关联查询多对一关联查询 项目案例项目案例:查询学号为1的学生,同时获取他所在班级的完整信息(项目源码见本书配套源码:第3章/多对一/mybatis32)(1)拷贝项目mybatis31为mybatis32接口IStudentDao中添加方法searchStudentsById(String id)。public Student s
7、earchStudentsById(int id);(2)配置映射文件ClassesMapper.xml,内容如下。方式一:多表联合查询。方式一:多表联合查询。select cid,cname,id,studentname,gender,age from classes,student where classes.cid=student.classno and student.id=#id方式二:多表单独查询。方式二:多表单独查询。select id,studentname,gender,age,classno from student where id=#idselect cid,cname
8、 from classes where cid=#cid 中查询出来的classno传递给中的column=classno 再把classno的值做为实参,传递给中的形参#cid方式2说明 3.3.1多对一的方式实现自连接多对一的方式实现自连接 项目案例项目案例:查询员工的信息及对应的上司信息。(项目源码见本书配套源码:第3章/自连接多对一方式/mybatis33)。思路分析思路分析:可将员工当作多方,上司当用一方。(1)修改数据库。添加一个表employee并插入测试数据:3.3 自连接自连接create table employee(empid double,empname varchar
9、(60),job varchar(60),leader double);insert into employee(empid,empname,job,leader)values(1,jack,clerk,3);insert into employee(empid,empname,job,leader)values(2,mike,salesman,3);insert into employee(empid,empname,job,leader)values(3,john,manager,4);insert into employee(empid,empname,job,leader)values
10、(4,smith,president,NULL);insert into employee(empid,empname,job,leader)values(5,rose,salesman,3);(2)创建实体类Employee。public class Employee private int empid;private String empname;private String job;private Employee leader;/省略setter,getter方法public String toString()return 员工编号:+getEmpid()+,员工姓名:+getEmpn
11、ame()+,员工职位:+getJob();可以发现,里面存在着嵌套,Employee里面的一个属性leader,本身就是Employee类型。(3)创建IEmployeeDao接口,添加方法findEmployeeAndLeaderById(int id)。public Employee findEmployeeAndLeaderById(int id);(4)修改Mybatis-config.xml配置文件。(5)创建映射文件EmployeeMapper。select*from employee where empid=#empid (6)接口实现类EmployeeDaoImpl.java
12、。(7)测试类TestEmployee1.java。public static void main(String args)findEmployeeAndLeaderById();public static void findEmployeeAndLeaderById()Scanner input=new Scanner(System.in);System.out.print(请输入要查询的员工编号:);int empid=input.nextInt();IEmployeeDao eDao=new EmployeeDaoImpl();Employee employee=eDao.findEmp
13、loyeeAndLeaderById(empid);Employee leader=employee.getLeader();System.out.println(employee.toString();System.out.println(他的上司是:+leader.toString();项目案例项目案例:查询某位领导及其直接下属员工。(项目源码见本书配套源码:第3章/自连接一对多方式/mybatis34)思路分析思路分析:可用一对多的方式来实现,员工(领导)当作一方,员工(下属)当作多方。3.3.2 一对多方式实现自连接一对多方式实现自连接(1)拷贝mybatis33为mybatis34修
14、改实体类,添加属性。private List employees;public List getEmployees()return employees;public void setEmployees(List employees)this.employees=employees;(2)创建IEmployeeDao接口,添加方法。public List findLeaderAndEmployeesById(int id);(3)映射文件EmployeeMapper,添加下面内容。select*from employee where leader=#empidselect*from employ
15、ee where empid=#empid(4)接口实现类EmployeeDaoImpl.java,添加方法findLeaderAndEmployeesById(int id)。(5)测试类。public static void findLeaderAndEmployeesById()Scanner input=new Scanner(System.in);System.out.print(请输入要查询的员工编号:);int empid=input.nextInt();EmployeeDaoImpl eDao=new EmployeeDaoImpl();Employee leader=eDao
16、.findLeaderAndEmployeesById(empid);List employees=leader.getEmployees();System.out.println(leader.toString();System.out.println(他的直接下属有:);for(Employee emp:employees)System.out.println(emp.toString();原理原理:多对多可以分拆成两个一对多来处理,需要一个中间表,各自与中间表实现一对多的关系。项目案例:项目案例:一个学生可以选人修多门课程,一门课程可以给多个学生选修,课程与学生之间是典型的多对多。实现查
17、询一个学生信息,同时查出他的所有选修课,还有实现查询一门课程信息,同时查出所有的选修了该课程的学生信息。(项目源码见本书配套源码:第3章/多对多/mybatis35)思路分析:思路分析:多对多需要第三表来体现,数据库中除了课程表,学生表,还需要学生课程表。3.4 多对多查询多对多查询(1)修改数据库。create table course(courseid double,coursename varchar(90);insert into course(courseid,coursename)values(1,java);insert into course(courseid,coursena
18、me)values(2,android);insert into course(courseid,coursename)values(3,PHP);create table studentcourse(id double,studentid double,courseid double );insert into studentcourse(id,studentid,courseid)values(1,1,1);insert into studentcourse(id,studentid,courseid)values(2,1,2);insert into studentcourse(id,s
19、tudentid,courseid)values(3,2,1);insert into studentcourse(id,studentid,courseid)values(4,2,2);insert into studentcourse(id,studentid,courseid)values(5,3,1);insert into studentcourse(id,studentid,courseid)values(6,3,2);insert into studentcourse(id,studentid,courseid)values(7,1,3);(2)拷贝mybatis34为mybat
20、is35新增实体类Course和修改实体类Student。Course类:public class Course private int courseid;private String coursename;private List students;/省略setter,getter方法public String toString()return 课程编号:+getCourseid()+,课程名称:+getCoursename();Student类:添加一个属性courses和getter,setter方法。private List courses;public List getCourses
21、()return courses;public void setCourses(List courses)this.courses=courses;(3)修改mybatis-config.xml配置文件。(4)在接口IStudentDao中添加一个方法searchStudentById(int id)。public Student searchStudentById(int id);(5)新建接口ICourseDao,添加一个方法searchCourseById(int id)。public Course searchCourseById(int id);(6)配置Mapper映射。Stude
22、ntMapper的配置。select student.id,studentname,gender,age,course.courseid,coursename from course,student,studentcourse where course.courseid=studentcourse.courseid and student.id=studentcourse.studentid and student.id=#idCourseMapper的配置:select id,studentname,gender,age,courseid,coursename from course,stu
23、dent,studentcourse where course.courseid=studentcourse.courseid and student.id=studentcourse.studentid and course.courseid=#courseid (7)实现类 StudentDaoImpl类,CourseDaoImpl类:(8)测试类TestStudent1.java public static void searchStudentById()IStudentDao studentDao=new StudentDaoImpl();Student student=student
24、Dao.searchStudentById(1);student.show();System.out.println(-该生选修了以下课程:-);List courses=student.getCourses();for(Course course:courses)System.out.println(course.toString();测试类TestCourse1.java public static void searchCourseById()ICourseDao courseDao=new CourseDaoImpl();Course course=courseDao.searchCourseById(1);System.out.println(course.toString();System.out.println(-该课程有以下学生选修:-);List students=course.getStudents();for(Student student:students)student.show();